sc

Check-in [65f2da3649]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Actual commit of "sc" source, missed pushing it to the old github acct
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | master | trunk
Files: files | file ages | folders
SHA3-256:65f2da36493ee3aaaef4f2f3dedfa250cf5ffaf24335bea78e136613f9b2467b
User & Date: vandys 2018-06-05 05:07:46
Context
2018-06-05
05:07
Actual commit of "sc" source, missed pushing it to the old github acct Leaf check-in: 65f2da3649 user: vandys tags: master, trunk
2017-11-15
14:32
Initial commit check-in: ecb24b94bb user: noreply@github.com tags: master, trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added Makefile.















>
>
>
>
>
>
>
1
2
3
4
5
6
7
CC=gcc
OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o gram.o lex.o
CFLAGS=-DSIMPLE -DSIGVOID
LIBS=-lm -lncurses -ltermcap

sc: $(OBJS)
	$(CC) $(CFLAGS) -o sc $(OBJS) $(LIBS)

Changes to README.md.

1
2










































































# sc
sc ASCII "Spreadsheet Calculator"












































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# sc
sc ASCII "Spreadsheet Calculator"

This is the old Spreadsheet Calculator, running in a terminal.
While it's never going to be confused with Excel, it actually
does the things you need for 99% of your tasks.

I have updated it a bit to compile with newer regex API's.

--Andy Valencia 11/15/2017

Original README follows:

=================================================

This is a much modified version of the public domain spread sheet sc,
posted several years ago by Mark Weiser as vc, originally by James Gosling.

Changes since my last version (5.1) are detailed at great length :-)
in CHANGES.

When you get it built, try "sc tutorial.sc" for a simple introduction
to the basic commands.

A new input parser program (psc) has been included.  This program
formats ascii files for use in the spread sheet.  If you don't have
getopts, there is a public domain version by Henry Spencer hidden away
in the VMS_NOTES file.

I have modified the makefile to make it easy for you to call the
program what you want (I saw at least five different names in
correspondence and on the net).  Just change "name=sc" and "NAME=SC" to
"name=myfavoritename" and "NAME=MYFAVORITENAME" and try "make
myfavoritename".

Similarly, you can make the documentation with "make myfavoritename.man".
"make install" will make and install the code in EXDIR.  The
installation steps and documentation all key off of the name.  The
makefile even changes the name in the nroffable man page.  If you don't
have nroff, you will have to change sc.man yourself.

This release has been tested against a Sequent S81 running DYNIX 3.0.14
(BSD 4.2) and an ICM-3216 with system V.3.  The ICM has a National Semi
32016.  Just check the makefile for the system flags.   I have heard
reports of lots of other machines that work. If you have problems with
lex.c, and don't care about arrow keys, define SIMPLE (-DSIMPLE in the
makefile).  SIMPLE causes the arrow keys to not be used.

Guidelines for Hackers:

If you want to send changes you have made to SC, please feel free to do
so.  If they work :-) and seem worthwhile, I'll put them in.  Please
refrain from wholesale "style" or "cleanup" changes.  It is easy to add
your changes but it makes it hard to merge in the next guy's stuff if
he used the release as a base.  Leave my $Revision:  identifiers alone-
they help me track what you used as a base.  If you check the code into
rcs, delete the "$"s on the Revison lines before you do.

You may not like 4 space indenting and curly braces on the "if" line,
but your code will look like that before it leaves my hands so you may
as well abide by the style in the code when you make your changes.  I
have also been known to break things trying to make them look "right".
If you do string functions, please, PLEASE pay attention to null
pointers, use xmalloc and xfree, and xfree those arguments.  And
don't forget to document your changes in both help.c and sc.doc.

Disclaimer:

Sc is not a product of Sequent Computer Systems.  It is supplied as
is with no warranty, express or implied, as a service to Usenet readers.
It is not copyrighted, either.  Have at it.

					Bob Bond

    Robert Bond 			uunet!sequent!rgb
    Sequent Computer Systems

Added cmds.c.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
/*	SC	A Spreadsheet Calculator
 *		Command routines
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *
 *		$Revision: 1.1 $
 */

#include <curses.h>
#include "sc.h"
#include <signal.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#ifdef SYSV3
extern void exit();
#else
extern int exit();
#endif

#define DEFCOLDELIM ':'

duprow()
{
    if (currow >= MAXROWS - 1 || maxrow >= MAXROWS - 1) {
	error ("The table can't be any bigger");
	return;
    }
    modflg++;
    currow++;
    openrow (currow);
    for (curcol = 0; curcol <= maxcol; curcol++) {
	register struct ent *p = tbl[currow - 1][curcol];
	if (p) {
	    register struct ent *n;
	    n = lookat (currow, curcol);
	    copyent ( n, p, 1, 0);
	}
    }
    for (curcol = 0; curcol <= maxcol; curcol++) {
	register struct ent *p = tbl[currow][curcol];
	if (p && (p -> flags & is_valid) && !p -> expr)
	    break;
    }
    if (curcol > maxcol)
	curcol = 0;
}

dupcol() 
{
    if (curcol >= MAXCOLS - 1 || maxcol >= MAXCOLS - 1) {
	error ("The table can't be any wider");
	return;
    }
    modflg++;
    curcol++;
    opencol (curcol);
    for (currow = 0; currow <= maxrow; currow++) {
	register struct ent *p = tbl[currow][curcol - 1];
	if (p) {
	    register struct ent *n;
	    n = lookat (currow, curcol);
	    copyent ( n, p, 0, 1);
	}
    }
    for (currow = 0; currow <= maxrow; currow++) {
	register struct ent *p = tbl[currow][curcol];
	if (p && (p -> flags & is_valid) && !p -> expr)
	    break;
    }
    if (currow > maxrow)
	currow = 0;
}

insertrow(arg)
register int arg;
{
    while (--arg>=0) openrow (currow);
}

deleterow(arg)
register int arg;
{
    flush_saved();
    erase_area(currow, 0, currow + arg - 1, maxcol);
    currow += arg;
    while (--arg>=0) closerow (--currow);
    sync_refs();
}

insertcol(arg)
register int arg;
{
    while (--arg>=0) opencol(curcol);
}

deletecol(arg)
register int arg;
{
    flush_saved();
    erase_area(0, curcol, maxrow, curcol + arg - 1);
    curcol += arg;
    while (--arg>=0) closecol (--curcol);
    sync_refs();
}

rowvalueize(arg)
register int arg;
{
    valueize_area(currow, 0, currow + arg - 1, maxcol);
}

colvalueize(arg)
register int arg;
{
    valueize_area(0, curcol, maxrow, curcol + arg - 1);
}

erase_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
    register int r, c;
    register struct ent **p;

    if (sr > er) {
	r = sr; sr = er; er= r;	
    }

    if (sc > ec) {
	c = sc; sc = ec; ec= c;	
    }

    if (sr < 0)
	sr = 0; 
    if (sc < 0)
	sc = 0;
    if (er >= MAXROWS)
	er = MAXROWS-1;
    if (ec >= MAXCOLS)
	ec = MAXCOLS-1;

    for (r = sr; r <= er; r++) {
	for (c = sc; c <= ec; c++) {
	    p = &tbl[r][c];
	    if (*p) {
		free_ent(*p);
		*p = 0;
	    }
	}
    }

}

valueize_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
    register int r, c;
    register struct ent *p;

    if (sr > er) {
	r = sr; sr = er; er= r;	
    }

    if (sc > ec) {
	c = sc; sc = ec; ec= c;	
    }

    if (sr < 0)
	sr = 0; 
    if (sc < 0)
	sc = 0;
    if (er >= MAXROWS)
	er = MAXROWS-1;
    if (ec >= MAXCOLS)
	ec = MAXCOLS-1;

    for (r = sr; r <= er; r++) {
	for (c = sc; c <= ec; c++) {
	    p = tbl[r][c];
	    if (p && p->expr) {
		efree(p->expr);
		p->expr = 0;
		p->flags &= ~is_strexpr;
	    }
	}
    }

}

pullcells(to_insert)
int to_insert;
{
    register struct ent *p, *n;
    register int deltar, deltac;
    int minrow, mincol;
    int mxrow, mxcol;
    int numrows, numcols;

    if (! to_fix)
    {
	error ("No data to pull");
	return;
    }

    minrow = MAXROWS; 
    mincol = MAXCOLS;
    mxrow = 0;
    mxcol = 0;

    for (p = to_fix; p; p = p->next) {
	if (p->row < minrow)
	    minrow = p->row;
	if (p->row > mxrow)
	    mxrow = p->row;
	if (p->col < mincol)
	    mincol = p->col;
	if (p->col > mxcol)
	    mxcol = p->col;
    }

    numrows = mxrow - minrow + 1;
    numcols = mxcol - mincol + 1;
    deltar = currow - minrow;
    deltac = curcol - mincol;

    if (to_insert == 'r') {
	insertrow(numrows);
	deltac = 0;
    } else if (to_insert == 'c') {
	insertcol(numcols);
	deltar = 0;
    }

    FullUpdate++;
    modflg++;

    for (p = to_fix; p; p = p->next) {
	n = lookat (p->row + deltar, p->col + deltac);
	(void) clearent(n);
	copyent( n, p, deltar, deltac);
	n -> flags = p -> flags & ~is_deleted;
    }
}

colshow_op()
{
    register int i,j;
    for (i=0; i<MAXCOLS; i++)
	if (col_hidden[i]) 
	    break;
    for(j=i; j<MAXCOLS; j++)
	if (!col_hidden[j])
	    break;
    j--;
    if (i>=MAXCOLS)
	error ("No hidden columns to show");
    else {
	(void) sprintf(line,"show %s:", coltoa(i));
	(void) sprintf(line + strlen(line),"%s",coltoa(j));
	linelim = strlen (line);
    }
}

rowshow_op()
{
    register int i,j;
    for (i=0; i<MAXROWS; i++)
	if (row_hidden[i]) 
	    break;
    for(j=i; j<MAXROWS; j++)
	if (!row_hidden[j]) {
	    break;
	}
    j--;

    if (i>=MAXROWS)
	error ("No hidden rows to show");
    else {
	(void) sprintf(line,"show %d:%d", i, j);
        linelim = strlen (line);
    }
}

/*
 * Given a row/column command letter, emit a small menu, then read a qualifier
 * character for a row/column command and convert it to 'r' (row), 'c'
 * (column), or 0 (unknown).  If ch is 'p', an extra qualifier 'm' is allowed.
 */

get_rcqual (ch)
    int ch;
{
    error ("%sow/column:  r: row  c: column%s",

	    (ch == 'i') ? "Insert r" :
	    (ch == 'a') ? "Append r" :
	    (ch == 'd') ? "Delete r" :
	    (ch == 'p') ? "Pull r" :
	    (ch == 'v') ? "Values r" :
	    (ch == 'z') ? "Zap r" :
	    (ch == 's') ? "Show r" : "R",

	    (ch == 'p') ? "  m: merge" : "");

    (void) refresh();

    switch (nmgetch())
    {
	case 'r':
	case 'l':
	case 'h':
	case ctl('f'):
	case ctl('b'):	return ('r');

	case 'c':
	case 'j':
	case 'k':
	case ctl('p'):
	case ctl('n'):	return ('c');

	case 'm':	return ((ch == 'p') ? 'm' : 0);

	case ESC:
	case ctl ('g'):	return (ESC);

	default:	return (0);
    }
    /*NOTREACHED*/
}

openrow (rs)
int rs;
{
    register    r;
    register struct ent **p;
    register    c;
    register	i;

    if (rs > maxrow) maxrow = rs;
    if (maxrow >= MAXROWS - 1 || rs > MAXROWS - 1) {
	error ("The table can't be any longer");
	return;
    }
    for (i = maxrow+1; i > rs; i--) {
	row_hidden[i] = row_hidden[i-1];
    }
    for (r = ++maxrow; r > rs; r--)
	for (c = maxcol + 1, p = &tbl[r][0]; --c >= 0; p++)
	    if (p[0] = p[-MAXCOLS])
		p[0] -> row++;
    p = &tbl[rs][0];
    for (c = maxcol + 1; --c >= 0;)
	*p++ = 0;
    FullUpdate++;
    modflg++;
}

closerow (r)
register r;
{
    register struct ent **p;
    register c;
    register int i;

    if (r > maxrow) return;

    p = &tbl[r][0];
    for (c=maxcol+1; --c>=0; ) {
	if (*p)
	    free_ent(*p);
	*p++ = 0;
    }

    for (i = r; i < MAXROWS - 1; i++) {
	row_hidden[i] = row_hidden[i+1];
    }

    while (r<maxrow) {
	for (c = maxcol+1, p = &tbl[r][0]; --c>=0; p++)
	    if (p[0] = p[MAXCOLS])
		p[0]->row--;
	r++;
    }

    p = &tbl[maxrow][0];
    for (c=maxcol+1; --c>=0; ) *p++ = 0;
    maxrow--;
    FullUpdate++;
    modflg++;
}

opencol (cs)
int cs;
{
    register r;
    register struct ent **p;
    register c;
    register lim = maxcol-cs+1;
    int i;

    if (cs > maxcol) maxcol = cs;
    if (maxcol >= MAXCOLS - 1 || cs > MAXCOLS - 1) {
	error ("The table can't be any wider");
	return;
    }
    for (i = maxcol+1; i > cs; i--) {
	fwidth[i] = fwidth[i-1];
	precision[i] = precision[i-1];
	col_hidden[i] = col_hidden[i-1];
    }
    /* fwidth[cs] = DEFWIDTH;
    precision[i] =  DEFPREC;  */

    for (r=0; r<=maxrow; r++) {
	p = &tbl[r][maxcol+1];
	for (c=lim; --c>=0; p--)
	    if (p[0] = p[-1])
		p[0]->col++;
	p[0] = 0;
    }
    maxcol++;
    FullUpdate++;
    modflg++;
}

closecol (cs)
int cs;
{
    register r;
    register struct ent **p;
    register struct ent *q;
    register c;
    register lim = maxcol-cs;
    int i;

    if (lim < 0) return;

    for (r=0; r<=maxrow; r++)
	if (q = tbl[r][cs]) {
	    free_ent(q);
	}

    for (r=0; r<=maxrow; r++) {
	p = &tbl[r][cs];
	for (c=lim; --c>=0; p++)
	    if (p[0] = p[1])
		p[0]->col--;
	p[0] = 0;
    }

    for (i = cs; i < MAXCOLS - 1; i++) {
	fwidth[i] = fwidth[i+1];
	precision[i] = precision[i+1];
	col_hidden[i] = col_hidden[i+1];
    }

    maxcol--;
    FullUpdate++;
    modflg++;
}

doend(rowinc, colinc)
int rowinc, colinc;
{
    register struct ent *p;
    int r, c;

    if (VALID_CELL(p, currow, curcol)) {
	r = currow + rowinc;
	c = curcol + colinc;
	if (r >= 0 && r < MAXROWS && 
	    c >= 0 && c < MAXCOLS &&
	    !VALID_CELL(p, r, c)) {
		currow = r;
		curcol = c;
	}
    }

    if (!VALID_CELL(p, currow, curcol)) {
        switch (rowinc) {
        case -1:
	    while (!VALID_CELL(p, currow, curcol) && currow > 0)
		currow--;
	    break;
        case  1:
	    while (!VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
		currow++;
	    break;
        case  0:
            switch (colinc) {
 	    case -1:
	        while (!VALID_CELL(p, currow, curcol) && curcol > 0)
		    curcol--;
	        break;
 	    case  1:
	        while (!VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
		    curcol++;
	        break;
	    }
            break;
        }

	error ("");	/* clear line */
	return;
    }

    switch (rowinc) {
    case -1:
	while (VALID_CELL(p, currow, curcol) && currow > 0)
	    currow--;
	break;
    case  1:
	while (VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
	    currow++;
	break;
    case  0:
	switch (colinc) {
	case -1:
	    while (VALID_CELL(p, currow, curcol) && curcol > 0)
		curcol--;
	    break;
	case  1:
	    while (VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
		curcol++;
	    break;
	}
	break;
    }
    if (!VALID_CELL(p, currow, curcol)) {
        currow -= rowinc;
        curcol -= colinc;
    }
}

doformat(c1,c2,w,p)
int c1,c2,w,p;
{
    register int i;

    if (w > COLS - RESCOL - 2) {
	error("Format too large - Maximum = %d", COLS - RESCOL - 2);
	w = COLS-RESCOL-2;
    }

    if (p > w) {
	error("Precision too large");
	p = w;
    }

    for(i = c1; i<=c2; i++)
	fwidth[i] = w, precision[i] = p;

    FullUpdate++;
    modflg++;
}

print_options(f)
FILE *f;
{
    if(
       autocalc &&
       propagation == 10 &&
       calc_order == BYROWS &&
       !numeric &&
       prescale == 1.0 &&
       !extfunc &&
       showcell &&
       showtop &&
       tbl_style == 0
      )
		return;		/* No reason to do this */

    (void) fprintf(f, "set");
    if(!autocalc) 
	(void) fprintf(f," !autocalc");
    if(propagation != 10)
	(void) fprintf(f, " iterations = %d", propagation);
    if(calc_order != BYROWS )
	(void) fprintf(f, " bycols");
    if (numeric)
	(void) fprintf(f, " numeric");
    if (prescale != 1.0)
	(void) fprintf(f, " prescale");
    if (extfunc)
	(void) fprintf(f, " extfun");
    if (!showcell)
	(void) fprintf(f, " !cellcur");
    if (!showtop)
	(void) fprintf(f, " !toprow");
    if (tbl_style)
	(void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
					tbl_style == LATEX ? "latex" :
					tbl_style == TEX ? "tex" : "0" );
    (void) fprintf(f, "\n");
}

printfile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
    FILE *f;
    char pline[1000];
    int plinelim;
    int pid;
    int fieldlen, nextcol;
    register row, col;
    register struct ent **p;
    char ch, lin[100];

    if (strcmp(fname, curfile) == 0) {
	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,
		"Confirm that you want to destroy the data base: (y,n)");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if (ch != 'y' && ch != 'Y') 
	    return;
    }

    f = openout(fname, &pid);

    if (f==0) {
	error ("Can't create file \"%s\"", fname);
	return;
    }
    for (row=r0;row<=rn; row++) {
	register c = 0;

	if (row_hidden[row])
	    continue;

	pline[plinelim=0] = '\0';
	for (p = &tbl[row][col=c0]; col<=cn;
	        p += nextcol-col, col = nextcol, c += fieldlen) {

	    nextcol = col+1;
	    if (col_hidden[col]) {
		fieldlen = 0;
		continue;
	    }

	    fieldlen = fwidth[col];
	    if (*p) {
		char *s;

		while (plinelim<c) pline[plinelim++] = ' ';
		plinelim = c;
		if ((*p)->flags&is_valid) {
		    (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
		                                precision[col], (*p)->v);
		    plinelim += strlen (pline+plinelim);
		}
		if (s = (*p)->label) {
		    int slen;
		    char *start, *last;
		    register char *fp;
		    struct ent *nc;

		    /* Figure out if the label slops over to a blank field */
		    slen = strlen(s);
		    while (slen > fieldlen && nextcol <= cn &&
			    !((nc = lookat(row,nextcol))->flags & is_valid) &&
			    !(nc->label)) {
			
	                if (!col_hidden[nextcol])
		 	    fieldlen += fwidth[nextcol];

			nextcol++;
		    }
		    if (slen > fieldlen)
			slen = fieldlen;
		    
		    /* Now justify and print */
		    start = (*p)->flags & is_leftflush ? pline + c
					: pline + c + fieldlen - slen;
		    last = pline + c + fieldlen;
		    fp = plinelim < c ? pline + plinelim : pline + c;
		    while (fp < start)
			*fp++ = ' ';
		    while (slen--)
			*fp++ = *s++;
		    if (!((*p)->flags & is_valid) || fieldlen != fwidth[col])
			while(fp < last)
			    *fp++ = ' ';
		    if (plinelim < fp - pline)
			plinelim = fp - pline;
		}
	    }
	}
	pline[plinelim++] = '\n';
	pline[plinelim] = 0;
	(void) fputs (pline, f);
    }

    closeout(f, pid);
}

tblprintfile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
    FILE *f;
    int pid;
    register row, col;
    register struct ent **p;
    char coldelim = DEFCOLDELIM;
    char ch, lin[100];

    if (strcmp(fname, curfile) == 0) {
	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,
		"Confirm that you want to destroy the data base: (y,n)");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if (ch != 'y' && ch != 'Y') 
	    return;
    }

    f = openout(fname, &pid);

    if (f==0) {
	error ("Can't create file \"%s\"", fname);
	return;
    }

    if ( tbl_style == TBL ) {
	fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
	fprintf(f,"tab(%c);\n",coldelim);
	for (col=c0;col<=cn; col++) fprintf(f," n");
	fprintf(f, ".\n");
	}
    else if ( tbl_style == LATEX ) {
	fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
	for (col=c0;col<=cn; col++) fprintf(f,"c");
	fprintf(f, "}\n");
	coldelim = '&';
	}
    else if ( tbl_style == TEX ) {
	fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
		progname, cn-c0+1);
	coldelim = '&';
	}

    for (row=r0; row<=rn; row++) {
	if ( tbl_style == TEX )
	    (void) fprintf (f, "\\+");
	
	for (p = &tbl[row][col=c0]; col<=cn; col++, p++) {
	    if (*p) {
		char *s;
		if ((*p)->flags&is_valid) {
		    (void) fprintf (f,"%.*f",precision[col],
				(*p)->v);
		}
		if (s = (*p)->label) {
	            (void) fprintf (f,"%s",s);
		}
	    }
	    if ( col < cn )
		(void) fprintf(f,"%c",coldelim);
	}
	if ( tbl_style == LATEX ) {
	    if ( row < rn ) (void) fprintf (f, "\\\\");
	    }
	else if ( tbl_style == TEX ) {
	    (void) fprintf (f, "\\cr");
	    }
	(void) fprintf (f,"\n");
    }

    if ( tbl_style == TBL )
    (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
    else if ( tbl_style == LATEX )
    (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
    else if ( tbl_style == TEX )
    (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);

    closeout(f, pid);
}

struct enode *
copye (e, Rdelta, Cdelta)
register struct enode *e;
int Rdelta, Cdelta;
{
    register struct enode *ret;
    if (e==0) {
        ret = 0;
    } else if (e->op & REDUCE) {
	int newrow, newcol;
	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
	ret->op = e->op;
	newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
					  e->e.r.left.vp->row+Rdelta;
	newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
					  e->e.r.left.vp->col+Cdelta;
	ret->e.r.left.vp = lookat (newrow, newcol);
	ret->e.r.left.vf = e->e.r.left.vf;
	newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
					   e->e.r.right.vp->row+Rdelta;
	newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
					   e->e.r.right.vp->col+Cdelta;
	ret->e.r.right.vp = lookat (newrow, newcol);
	ret->e.r.right.vf = e->e.r.right.vf;
    } else {
	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
	ret->op = e->op;
	switch (ret->op) {
	case 'v':
		{
		    int newrow, newcol;
		    newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
						 e->e.v.vp->row+Rdelta;
		    newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
						 e->e.v.vp->col+Cdelta;
		    ret->e.v.vp = lookat (newrow, newcol);
		    ret->e.v.vf = e->e.v.vf;
		    break;
		}
	case 'k':
		ret->e.k = e->e.k;
		break;
	case 'f':
		ret->e.o.right = copye (e->e.o.right,0,0);
		ret->e.o.left = 0;
 		break;
	case '$':
		ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
		(void) strcpy(ret->e.s, e->e.s);
		break;
	default:
		ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
		ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
		break;
	}
    }
    return ret;
}

/*
 * sync_refs and syncref are used to remove references to
 * deleted struct ents.  Note that the deleted structure must still
 * be hanging around before the call, but not referenced by an entry
 * in tbl.  Thus the free_ent, fix_ent calls in sc.c
 */

sync_refs ()
{
    register i,j;
    register struct ent *p;
    sync_ranges();
    for (i=0; i<=maxrow; i++)
	for (j=0; j<=maxcol; j++)
	    if ((p=tbl[i][j]) && p->expr)
		syncref(p->expr);
}


syncref(e)
register struct enode *e;
{
    if (e==0)
	return;
    else if (e->op & REDUCE) {
 	e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
 	e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
    } else {
	switch (e->op) {
	case 'v':
		e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
		break;
	case 'k':
		break;
	case '$':
		break;
	default:
		syncref(e->e.o.right);
		syncref(e->e.o.left);
		break;
	}
    }
}

hiderow(arg)
int arg;
{
    register int r1;
    register int r2;

    r1 = currow;
    r2 = r1 + arg - 1;
    if (r1 < 0 || r1 > r2) {
	error ("Invalid range");
	return;
    }
    if (r2 > MAXROWS-2) {
	error ("You can't hide the last row");
	return;
    }
    FullUpdate++;
    while (r1 <= r2)
	row_hidden[r1++] = 1;
}

hidecol(arg)
int arg;
{
    register int c1;
    register int c2;

    c1 = curcol;
    c2 = c1 + arg - 1;
    if (c1 < 0 || c1 > c2) {
	error ("Invalid range");
	return;
    }
    if (c2 > MAXCOLS-2) {
	error ("You can't hide the last column");
	return;
    }
    FullUpdate++;
    while (c1 <= c2)
	col_hidden[c1++] = 1;
}

showrow(r1, r2)
int r1, r2;
{
    if (r1 < 0 || r1 > r2) {
	error ("Invalid range");
	return;
    }
    if (r2 > MAXROWS-1) {
	r2 = MAXROWS-1;
    }
    FullUpdate++;
    while (r1 <= r2)
	row_hidden[r1++] = 0;
}

showcol(c1, c2)
int c1, c2;
{
    if (c1 < 0 || c1 > c2) {
	error ("Invalid range");
	return;
    }
    if (c2 > MAXCOLS-1) {
	c2 = MAXCOLS-1;
    }
    FullUpdate++;
    while (c1 <= c2)
	col_hidden[c1++] = 0;
}

/* Open the output file, setting up a pipe if needed */

FILE *
openout(fname, rpid)
char *fname;
int *rpid;
{
    int pipefd[2];
    int pid;
    FILE *f;

    while (*fname && (*fname == ' '))  /* Skip leading blanks */
	fname++;

    if (*fname != '|') {		/* Open file if not pipe */
	*rpid = 0;
	return(fopen(fname, "w"));
    }

    fname++;				/* Skip | */
    if ( pipe (pipefd) < 0) {
	error("Can't make pipe to child");
	*rpid = 0;
	return(0);
    }

    deraw();
#ifdef VMS
    fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
#else /* VMS */

    if ((pid=fork()) == 0)			  /* if child  */
    {
	(void) close (0);			  /* close stdin */
	(void) close (pipefd[1]);
	(void) dup (pipefd[0]);		  /* connect to pipe input */
	(void) signal (SIGINT, SIG_DFL);	  /* reset */
	(void) execl ("/bin/sh", "sh", "-c", fname, 0);
	exit (-127);
    }
    else				  /* else parent */
    {
	*rpid = pid;
	f = fdopen (pipefd[1], "w");
	if (f == 0)
	{
	    (void) kill (pid, -9);
	    error ("Can't fdopen output");
	    (void) close (pipefd[1]);
	    *rpid = 0;
	    return(0);
	}
    }
#endif /* VMS */
    return(f);
}

closeout(f, pid)
FILE *f;
int pid;
{
    int temp;

    (void) fclose (f);
    if (pid) {
         while (pid != wait(&temp)) /**/;
	 (void) printf("Press RETURN to continue ");
	 (void) fflush(stdout);
	 (void) nmgetch();
	 goraw();
    }
}

copyent(n,p,dr,dc)
	    register struct ent *n, *p;
	    int dr, dc;
{
    if(!n||!p){error("internal error");return;}
    n -> v = p -> v;
    n -> flags = p -> flags;
    n -> expr = copye (p -> expr, dr, dc);
    n -> label = 0;
    if (p -> label) {
	n -> label = (char *)
		xmalloc  ((unsigned) (strlen (p -> label) + 1));
	(void) strcpy (n -> label, p -> label);
    }
}

write_fd (f, r0, c0, rn, cn)
register FILE *f;
int r0, c0, rn, cn;
{
    register struct ent **p;
    register r, c;

    (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
    (void) fprintf (f, "Calculator.\n");
    (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
    print_options(f);
    for (c=0; c<MAXCOLS; c++)
	if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
	    (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
    for (c=c0; c<cn; c++) {
        if (col_hidden[c]) {
            (void) fprintf(f, "hide %s\n", coltoa(c));
        }
    }
    for (r=r0; r<=rn; r++) {
	if (row_hidden[r]) {
	    (void) fprintf(f, "hide %d\n", r);
	}
    }

    write_range(f);

    if (mdir) 
	    (void) fprintf(f, "mdir \"%s\"\n", mdir);
    for (r=r0; r<=rn; r++) {
	p = &tbl[r][c0];
	for (c=c0; c<=cn; c++, p++)
	    if (*p) {
		if ((*p)->label) {
		    edits(r,c);
		    (void) fprintf(f, "%s\n",line);
		}
		if ((*p)->flags&is_valid) {
		    editv (r, c);
		    (void) fprintf (f, "%s\n",line);
		}
	    }
    }
}

writefile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
    register FILE *f;
    char save[1024];
    int pid;

#ifndef VMS
    if (Crypt) {
	return (cwritefile(fname, r0, c0, rn, cn));
    }
#endif /* VMS */

    if (*fname == 0) fname = &curfile[0];

    (void) strcpy(save,fname);

    f = openout(fname, &pid);
    if (f == 0) {
	error ("Can't create file \"%s\"", fname);
	return (-1);
    }

    write_fd(f, r0, c0, rn, cn);
    
    closeout(f, pid);

    if (!pid) {
        (void) strcpy(curfile, save);
        modflg = 0;
        error("File \"%s\" written.",curfile);
    }

    return (0);
}

readfile (fname,eraseflg)
char *fname;
int eraseflg;
{
    register FILE *f;
    char save[1024];

    if (*fname == '*' && mdir) { 
       (void) strcpy(save, mdir);
       *fname = '/';
       (void) strcat(save, fname);
    } else {
        if (*fname == 0)
	    fname = &curfile[0];
        (void) strcpy(save,fname);
    }

#ifndef VMS
    if (Crypt)  {
	creadfile(save, eraseflg);
	return;
    }
#endif /* VMS */

    if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;

    f = fopen (save, "r");
    if (f==0) {
	error ("Can't read file \"%s\"", save);
	return;
    }

    if (eraseflg) erasedb ();

    loading++;
    while (fgets(line,sizeof line,f)) {
	linelim = 0;
	if (line[0] != '#') (void) yyparse ();
    }
    --loading;
    (void) fclose (f);
    linelim = -1;
    modflg++;
    if (eraseflg) {
	(void) strcpy(curfile,save);
	modflg = 0;
    }
    EvalAll();
}

erasedb ()
{
    register r, c;
    for (c = 0; c<=maxcol; c++) {
	fwidth[c] = DEFWIDTH;
	precision[c] = DEFPREC;
    }

    for (r = 0; r<=maxrow; r++) {
	register struct ent **p = &tbl[r][0];
	for (c=0; c++<=maxcol; p++)
	    if (*p) {
		if ((*p)->expr) efree ((*p) -> expr);
		if ((*p)->label) xfree ((char *)((*p) -> label));
		xfree ((char *)(*p));
		*p = 0;
	    }
    }
    maxrow = 0;
    maxcol = 0;
    clean_range();
    FullUpdate++;
}

backcol(arg)
	int arg;
{
    while (--arg>=0) {
	if (curcol)
	    curcol--;
	else
	    {error ("At column A"); break;}
	while(col_hidden[curcol] && curcol)
	    curcol--;
    }
}

forwcol(arg)
	int arg;
{
    while (--arg>=0) {
	if (curcol < MAXCOLS - 1)
	    curcol++;
	else
	    {error ("The table can't be any wider"); break;}
	while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
	    curcol++;
    }
}

forwrow(arg)
	int arg;
{
    while (--arg>=0) {
	if (currow < MAXROWS - 1)
	    currow++;
	else
	    {error ("The table can't be any longer"); break;}
	while (row_hidden[currow]&&(currow<MAXROWS-1))
	    currow++;
    }
}

backrow(arg)
	int arg;
{
    while (--arg>=0) {
	if (currow)
	    currow--;
	else
	    {error ("At row zero"); break;}
	while (row_hidden[currow] && currow)
	    currow--;
    }
}


/*
 * Show a cell's label string or expression value.  May overwrite value if
 * there is one already displayed in the cell.  Created from old code in
 * update(), copied with minimal changes.
 */

showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
    char *string;	/* to display */
    int leftflush;	/* or rightflush */
    int hasvalue;	/* is there a numeric value? */
    int row, col;	/* spreadsheet location */
    int *nextcolp;	/* value returned through it */
    int mxcol;		/* last column displayed? */
    int *fieldlenp;	/* value returned through it */
    int r, c;		/* screen row and column */
{
    register int nextcol  = *nextcolp;
    register int fieldlen = *fieldlenp;

    char field[1024];
    int  slen;
    char *start, *last;
    register char *fp;
    struct ent *nc;

    /* This figures out if the label is allowed to
       slop over into the next blank field */

    slen = strlen (string);
    while ((slen > fieldlen) && (nextcol <= mxcol) &&
	   !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
	   !(nc->label)) {

	if (! col_hidden [nextcol])
	    fieldlen += fwidth [nextcol];

	nextcol++;
    }
    if (slen > fieldlen)
	slen = fieldlen;

    /* Now justify and print */
    start = leftflush ? field : field + fieldlen - slen;
    last = field+fieldlen;
    fp = field;
    while (fp < start)
	*fp++ = ' ';
    while (slen--)
	*fp++ = *string++;
    if ((! hasvalue) || fieldlen != fwidth[col]) 
	while (fp < last)
	    *fp++ = ' ';
    *fp = 0;
#ifdef VMS
    mvaddstr(r, c, field);	/* this is a macro */
#else
    (void) mvaddstr(r, c, field);
#endif

    *nextcolp  = nextcol;
    *fieldlenp = fieldlen;
}
etype(e)
register struct enode *e;
{

    if (e==0) return 0;
    switch (e->op) {
    case '+': case '-': case '*': case '/': case '%': case '^':
    case '<': case '=': case '>': case '&': case '|': case 'm':
    case '~': case 'k': case INDEX:
    case REDUCE | '+': case REDUCE | '*': case REDUCE | 'a':
    case REDUCE | 's': case REDUCE | MAX: case REDUCE | MIN:
    case ACOS: case ASIN: case ATAN: case ATAN2: case CEIL:
    case COS: case EXP: case FABS: case FLOOR: case HYPOT:
    case LOG: case LOG10: case POW: case SIN: case SQRT:
    case TAN: case DTR: case RTD: case RND: case FV: case PV:
    case PMT: case HOUR: case MINUTE: case SECOND: case MONTH:
    case DAY: case YEAR: case NOW: case STON: case EQS:
    case LMAX: case LMIN: case NVAL: case LOOKUP:
        return (NUM);

    case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
      case EXT: case SVAL: case SUBSTR: case STLOOKUP:
        return (STR);

    case 'f':  case '?':
        return(etype(e->e.o.left));

    case O_VAR: {
	register struct ent *p;
	p = e->e.v.vp;
	if (p->expr) 
	    return(p->flags & is_strexpr ? STR : NUM);
	else if (p->label)
	    return(STR);
	else
	    return(NUM);
	}

    default:
	return(NUM);
    }
}

Added crypt.c.

























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
 * Encryption utilites
 * Bradley Williams	
 * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams
 * $Revision: 1.1 $
 */

#include <stdio.h>
#include <curses.h>

#if defined(BSD42) || defined(BSD43)
#include <sys/file.h>
#else
#include <fcntl.h>
#endif

#include "sc.h"

char        *strcpy();

#ifdef SYSV3
void exit();
#endif

int         Crypt = 0;

creadfile (save, eraseflg)
char *save;
int  eraseflg;
{
    register FILE *f;
    int pipefd[2];
    int fildes;
    int pid;

    if (eraseflg && strcmp(save, curfile) && modcheck(" first")) return;

    fildes = open (save, O_RDONLY, 0);
    if (fildes < 0)
    {
	error ("Can't read file \"%s\"", save);
	return;
    }

    if (eraseflg) erasedb ();

    if (pipe(pipefd) < 0) {
	error("Can't make pipe to child");
	return;
    }

    deraw();
    if ((pid=fork()) == 0)			  /* if child  */
    {
	(void) close (0);		  /* close stdin */
	(void) close (1);		  /* close stdout */
	(void) close (pipefd[0]);	  /* close pipe input */
	(void) dup (fildes);		  /* standard in from file */
	(void) dup (pipefd[1]);		  /* connect to pipe */
	(void) fprintf (stderr, " ");
	(void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
	exit (-127);
    }
    else				  /* else parent */
    {
	(void) close (fildes);
	(void) close (pipefd[1]);	  /* close pipe output */
	f = fdopen (pipefd[0], "r");
	if (f == 0)
	{
	    (void) kill (pid, -9);
	    error ("Can't fdopen file \"%s\"", save);
	    (void) close (pipefd[0]);
	    return;
	}
    }

    loading++;
    while (fgets(line,sizeof line,f)) {
	linelim = 0;
	if (line[0] != '#') (void) yyparse ();
    }
    --loading;
    (void) fclose (f);
    (void) close (pipefd[0]);
    while (pid != wait(&fildes)) /**/;
    goraw();
    linelim = -1;
    modflg++;
    if (eraseflg) {
	(void) strcpy (curfile, save);
	modflg = 0;
    }
    EvalAll();
}

cwritefile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
    register FILE *f;
    int pipefd[2];
    int fildes;
    int pid;
    char save[1024];
    char *fn;


    if (*fname == 0) fname = &curfile[0];

    fn = fname;
    while (*fn && (*fn == ' '))  /* Skip leading blanks */
	fn++;

    if ( *fn == '|' ) {
	error ("Can't have encrypted pipe");
	return(-1);
	}

    (void) strcpy(save,fname);

    fildes = open (save, O_WRONLY|O_CREAT, 0600);
    if (fildes < 0)
    {
	error ("Can't create file \"%s\"", save);
	return(-1);
    }

    if (pipe (pipefd) < 0) {
	error ("Can't make pipe to child\n");
	return(-1);
    }

    deraw();
    if ((pid=fork()) == 0)			  /* if child  */
    {
	(void) close (0);			  /* close stdin */
	(void) close (1);			  /* close stdout */
	(void) close (pipefd[1]);		  /* close pipe output */
	(void) dup (pipefd[0]);			  /* connect to pipe input */
	(void) dup (fildes);			  /* standard out to file */
	(void) fprintf (stderr, " ");
	(void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
	exit (-127);
    }
    else				  /* else parent */
    {
	(void) close (fildes);
	(void) close (pipefd[0]);		  /* close pipe input */
	f = fdopen (pipefd[1], "w");
	if (f == 0)
	{
	    (void) kill (pid, -9);
	    error ("Can't fdopen file \"%s\"", save);
	    (void) close (pipefd[1]);
	    return(-1);
	}
    }

    write_fd(f, r0, c0, rn, cn);

    (void) fclose (f);
    (void) close (pipefd[1]);
    while (pid != wait(&fildes)) /**/;
    (void) strcpy(curfile,save);

    modflg = 0;
    error ("File \"%s\" written", curfile);
    goraw();
    return(0);
}

Added doc/bsd_bugs.







































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

My well known but much maligned position on this is that you should
all fix your curses include file per Dr. Goldman's recommendations.
Consider it to be my bit to make the world cleaner.

						Bob
---------------------------------------------------------------------------
Bob--

     sc/vc compiled and ran fine on a VAX running 4.3 BSD at my site.  However,
it compiled, but screwed up the nl()/nonl() stuff, when run on my MicroVAX II
running Ultrix 1.2; the same problem occurred on a VAX running vanilla 4.2 BSD.
I traced it to a bug in the nl()/nonl() definitions in /usr/include/curses.h
that appears to exist only in the 4.2 BSD and Ultrix 1.X versions of that file.
I suspect that someone had fixed those definitions on the 4.2 BSD system you
tested it on.  (In fact, on a Sun 2 at my site running Sun UNIX 3.0 [basically
4.2 BSD with Sun enhancements], the nl()/nonl() stuff in /usr/include/curses.h
has been fixed [by Sun].  I haven't tried compiling sc/vc on it yet, however.) 

     The following patch to sc.c is necessary for vanilla 4.2 BSD machines and
Ultrix 1.2 (and presumably Ultrix 1.0 and 1.1) machines: 

*** sc.c	Tue Jan 27 15:54:31 1987
--- sc.c.new	Tue Jan 27 15:55:06 1987
***************
*** 14,19 ****
--- 14,26 ----
  #include <curses.h>
  
+ #ifdef BSD42
+ #undef nl
+ #undef nonl
+ #define nl()	 (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
+ #define nonl()	 (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
+ #endif
+ 
  #ifdef BSD42
  #include <strings.h>
  #else
  #ifndef SYSIII

Perhaps you should post it to comp.sources.d.  Thanks.

--Eric
-------------------------------------------
  Eric S. Goldman, M.D.
  UCSF School of Medicine
  INET: goldman@cope.ucsf.edu
  UUCP: ...ucbvax!ucsfcgl!cope.ucsf!goldman
  BITNET: GOLDMAN@UCSFCOPE.BITNET

Added doc/changes.





































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
CHANGES BETWEEN 5.1 and 6.1:

Andy Valencia -
	xmalloc aligns data to a double boundary.

Lawrence Cipriani -
	Fixed a bug in the "do you want to save this" sequence.

Soren Lundsgaard -
	A null pointer derefrence.

Rick Perry -
	Cleaned up a problem with modchk() in sc.c.

Gregory Bond -
	Added code for multi argument versions of @min and @max.

Tad Mannes -
	Added code to save/restore hidden rows and columns when the
	data base is saved or restored.

Marius Olafsson -
	INTERNATIONAL changes.  Allows full 8 bit characters (if
	curses supports them.)

Kurt Horton -
	Added support for @pv, @fv and @pmt financial functins.
	Tested lots of different systems, linting.

John Campbell -
	Support for VMS.  See VMS_NOTES.

Peter King -
	 User selection of row or column order for recalculation.
		Also affects order of traversing regions in /f and /r
	 User setting of automatic or manual recalculation.
	 User setting of number of times to try recalculation.
	 + and - commands when in non-numeric mode to do 
		increment and decrement operations.
	@index, @stindex, @atan2, @lookup  functions.
	Save/restore options.
	Support for TeX, LaTeX, and better support for tbl in "T" cmd.
	Provision of a copyent function to copy entries (same code repeated
		in several locations)
	Forwrow, backrow, forwcol, backcol functions to replace
		repeated code
	Correct interpretation of ESCAPE or ^G as an abort when in a 
		two character command such as 'ar' or 'ac'
	Cleanup in eval() - catches non-trap function errors.

Bob Bond - 
       Added search options to "g".
       Added supression of hidden columns to "W"
       Added the mod operator "%"
       New help functions.
       Constant prescale "$"
       Added string matching to @lookup.
       Some more bug fixes.
       Testing, integration, documentation.

Alan Silverstein-
	Greatly revised the manual entry.
	Added menus for ^E command and row/column commands, which
	involved a bunch of code cleanup.

	Changed top row display to clearly indicate string labels
	versus number parts, and to distinguish string functions from
	constant labels.

	When the character cursor is on a cell (not topline), ^H
	(backspace) is like ^B (move back one cell), rather than being
	ignored.

	When the character cursor is on a cell (not topline), ^I (tab)
	is like ^F (move forward one cell), rather than being ignored.
	^R is no longer identical with ^L.  Now ^R highlights all cells
	which should be entered by a user because they contain constant
	numeric values (not the result of a numeric expression).

	Added a ^X command, similar to ^R, which highlights cells which
	have expressions.  It also displays the expressions in the
	highlighted cells as left-justified strings, instead of the
	label and/or value of the cell.

	Added indirection functions (@nval() and @sval()) for simple
	table lookups.  Given a column name and row number, they return
	the numeric or string value of the selected cell.

	Added external functions (@ext()) for non-trivial
	computations.  Given a command name and argument, it calls the
	command and reads back one output line.

	Added a ^T,e command to toggle enabling of external functions.

	Changed ^T,t to only control the top line display, and added
	^T,c to control current cell highlighting.  (Separated the
	functions.)

	"!" (shell escape) gives a vi-style warning if there were any
	changes since the last write.  (No change to manual entry.)

	Fixed some startup, error, and prompt messages to be cleaner
	and/or more consistent.  (No changes to manual entry.)

	Fixed a bug:  If @substr() upper bound (third parameter) is
	past the end of the string operand, return the substring
	through the end of the string, rather than returning a null
	string.

	Fixed a bug:  Reset SIGINT to default after forking before
	calling shell escape program and before starting pipeline (for
	commands which support this).  Didn't reset SIGINT before
	calling crypt and external functions because in both cases it
	should be irrelevant.  (No change to manual entry.)

Added doc/psc.doc.



































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
.\" $Revision $
.TH PPNAME 1
.SH NAME
ppname \- prepare pname files
.SH SYNOPSIS
.B ppname
[
.I -Lkr
]
[
.I -s cell
]
[
.I -R n
]
[
.I -C n
]
[
.I -n n
]
[
.I -d c
]

.SH DESCRIPTION
.I Ppname
is used to prepare data for input to the spread sheet calculator
.I pname(1).
It accepts normal ascii data on standard input.  Standard output
is a
.I pname
file.
With no options, 
.I ppname
starts the spread sheet in cell A0.  Strings are right justified.
All data on a line is entered on the same row; new input lines
cause the output row number to increment by one.  The default delimiters
are tab and space.  The column formats are set to one larger
than the number of columns required to hold the largest value
in the column.

Options:

.IP "\-L"
Left justify strings.

.IP "\-k"
Keep all delimiters.  This option causes the output cell to change on
each new delimiter encountered in the input stream.   The default
action is to condense multiple delimters to one, so that the cell only
changes once per input data item.

.IP "\-r"
Output the data by row first then column.  For input consisting of a single
column, this
option will result in output of one row with multiple columns
instead of a single
column spread sheet.

.IP "\-s cell"
Start the top left corner of the spread sheet in 
.I cell.
For example, 
.I "-s B33"
will arrange the output data so that the
spread sheet starts in column B, row 33.

.IP "\-R n"
Increment by
.I n 
on each new output row.

.IP "\-C n"
Increment by
.I n 
on each new output column.

.IP "\-n n"
Output 
.I n
rows before advancing to the next column.  This option is used when
the input is arranged in a single column and the spread sheet is to
have multiple columns, each of which is to be length
.I n.

.IP "\-d c"
Use the single character
.I c
as the delimiter between input fields.

.SH SEE ALSO
pname(1)

.SH AUTHOR

Robert Bond

Added doc/sc.doc.













































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
.\" Warning:  The string "pname" is converted to the true program name
.\" by the makefile, throughout this document.
.\"
.\" Warning:  The order of presentation of commands largely matches the
.\" help screen built into the program.
.\"
.\" Conventions:
.\" - pname italicized and never uppercased (it's a proper name).
.\" - Refer to lists of commands in the same order as introduced.
.\" - Command and function names bold when introduced, italicized in all
.\"   other places if possible, or in `` '' if not.
.\" - Cell names italicized except when used in expressions; row numbers
.\"   and column names not italicized.
.\" - Use `` '' rather than " " except referring to literal input or output.
.\" - TPs use default indent except for function names, then 18.
.\" - Smallify uppercase strings.
.\" - Avoid passive voice and third person.
.\" $Revision: 1.1 $
.\"
.TH PNAME 1
.SH NAME
pname \- spreadsheet calculator
.SH SYNOPSIS
.B pname
[
.B -c
]
[
.B -m
]
[
.B -n
]
[
.B -r
]
[
.B -x
]
[
.I file
]
.\" ==========
.SH DESCRIPTION
The spreadsheet calculator
.I pname
is based on rectangular tables much like a financial spreadsheet.
When invoked it presents you with a table
organized as rows and columns of cells.
If invoked without a
.I file
argument, the table is initially empty.
Otherwise
.I file
is read in (see the
.I Get
command below).
Each cell may have associated with it
a numeric value,
a label string,
and/or an expression (formula)
which evaluates to a numeric value or label string,
often based on other cell values.
.\" ----------
.PP
Options are:
.\" ----------
.TP
.B \-c
Start the program with the recalculation being done in column order.
.\" ----------
.TP
.B \-m
Start the program with automatic recalculation disabled.
The spreadsheet will be recalculated only when the ``@'' command is used.
.\" ----------
.TP
.B \-n
Start the program in quick numeric entry mode (see below).
.\" ----------
.TP
.B \-r
Start the program with the recalculation being done in row
order (default option).
.\" ----------
.TP
.B \-x
Cause the
.I Get
and
.I Put
commands (see below) to encrypt and decrypt data files.
.\" ----------
.PP
All of these options can be changed with the
.I ^T
and 
.I S
commands (see below) while
.I pname
is running.  Options specified when
.I pname 
is invoked
override options saved in the data file.
.\" ==========
.SS "General Information"
.\" ----------
The screen is divided into four regions.
The top line is for entering commands and displaying cell values.
The second line is for messages from
.IR pname .
The third line and the first four columns show the column and row numbers,
from which are derived cell addresses, e.g.
.I A0
for the cell in column A, row 0.
Note that column names are case-insensitive: you can enter
.I A0
or
.IR a0 .
.\" ----------
.PP
The rest of the screen forms a window looking at a portion of the table.
The total number of display rows and columns available,
hence the number of table rows and columns displayed,
is set by
.IR curses (3)
and may be overridden by setting the
.SM LINES
and
.SM COLUMNS
environment variables, respectively.
.\" ----------
.PP
The screen has two cursors:
a cell cursor, indicated by a highlighted cell and a ``<'' on the screen,
and a character cursor, indicated by the terminal's hardware cursor.
The cell and character cursors are often the same.
They differ when you type a command on the top line.
.\" ----------
.PP
If a cell's numeric value is wider than the column width (see the
.I f
command), the cell is filled with asterisks.
If a cell's label string is wider than the column width,
it is truncated at the start of the next non-blank cell in the row, if any.
.\" ----------
.PP
Cursor control commands and row and column commands
can be prefixed by a numeric argument
which indicates how many times the command is to be executed.
You can type
.I ^U
before a repeat count if quick numeric entry mode is enabled
or if the number is to be entered
while the character cursor is on the top line.
.\" ----------
.PP
Commands which use the terminal's control key, such as
.IR ^N ,
work both when a command is being typed and when in normal mode.
.\" ==========
.SS "Changing Options"
.\" ----------
\0 \" exactly one blank line (hard to get)
.PD 0
.TP
.BI ^T o
Toggle options.
This command allows you to switch the state of one option selected by
.IR o .
A small menu lists the choices for
.I o
when you type
.IR ^T .
The options selected are saved when the data and formulas are saved
so that you will have the same setup next time you enter the
spreadsheet. 
.PD
.RS
.\" ----------
.TP
.B a
Automatic Recalculation.
When set, each change in the spreadsheet causes the entire spreadsheet
be recalculated.  Normally this is not noticeable, but for very large
spreadsheets, it may be faster to clear automatic recalculation mode and
update the spreadsheet via explicit ``@'' commands.  Default is 
automatic recalculation on.
.\" ----------
.TP
.B c
Current cell highlighting.
If enabled, the current cell is highlighted
(using the terminal's standout mode, if available)
in addition to being marked by the cell cursor.
.\" ----------
.TP
.B e
External function execution.
When disabled, external functions (see
.IR @ext ()
below) are not called.
This saves a lot of time at each screen update.
External functions are disabled by default.
If disabled, and external functions are used anywhere,
a warning is printed each time the screen is updated,
and the result of
.IR @ext ()
is the value from the previous call, if any, or a null string.
.\" ----------
.TP
.B n
Quick numeric entry.
If enabled,
a typed digit is assumed to be
the start of a numeric value for the current cell,
not a repeat count, unless preceded by
.IR ^U .
.\" ----------
.TP
.B t
Top line display.
If enabled,
the name and value of the current cell is displayed on the top line.
If there is an associated label string,
the first character of the string value
is ``<'' for a leftstring or ``>'' for a rightstring (see below),
followed by "\fIstring\fP" for a constant string
or
.RI { expr }
for a string expression.
If the cell has a numeric value,
it follows as
.RI [ value ],
which may be a constant or expression.
.\" ----------
.TP
.B x
Encryption.
See the
.B \-x
option.
.\" ----------
.TP
.B $
Dollar prescale.
If enabled, all numeric
.B constants
(not expressions) which you enter are multipled by 0.01
so you don't have to keep typing the decimal point
if you enter lots of dollar figures.
.RE
.\" ----------
\0 \" exactly one blank line (hard to get)
.PD 0
.TP
.B S
Set options.  This command allows you to set various options.
A small menu lists the options that cannot be changed through
.I ^T
above.
.PD
.RS
.TP
.BR byrows /  bycols
Specify the order cell evaluation when updating.  These options also affect
the order in which cells are filled (see 
.IR /f )
and whether a row or column is cleared by an 
.I x
command.
.TP
.BI iterations =n
Set the maximum number of recalculations before
the screen is displayed again. 
.I Iterations
is set to 10 by default.
.TP
.BI tblstyle =s
Control the output of the 
.I T
command.
.I s
can be:
.B 0
(default) to give colon delimited fields, with no 
.I tbl
control lines;
.B tbl
to give colon delimited fields, with
.IR tbl (1)
control lines;
.B latex
to give a
.I LaTeX
tabular environment; and
.B tex
to give a
.I TeX
simple tabbed alignment with ampersands as delimiters.
.PP
Other
.I Set
options are normally used only in 
.I pname
data files since they are available through 
.IR ^T .
You can also use them interactively
.TP
.BR autocalc / !autocalc
Set/clear auto recalculation mode.
.TP
.BR numeric / !numeric
Set/clear numeric mode.
.TP
.BR prescale / !prescale
Set/clear numeric prescale mode.
.TP
.BR extfun / !extfun
Enable/disable external functions.
.TP
.BR cellcur / !cellcur
Set/clear current cell highlighting mode.
.TP
.BR toprow /  !toprow
Set/clear top row display mode.
.RE
.\" ==========
.SS "Cursor Control Commands"
.\" ----------
\0 \" exactly one blank line (hard to get)
.PD 0
.TP
.B ^P
Move the cell cursor up to the previous row.
.PD
.\" ----------
.TP
.B ^N
Move the cell cursor down to the next row.
.\" ----------
.TP
.B ^B
Move the cell cursor backward one column.
.\" ----------
.TP
.B ^F
Move the cell cursor forward one column.
.\" ----------
.TP
.B "h, j, k, l"
If the character cursor is not on the top line, these are alternate,
.IR vi -compatible
cell cursor controls (left, down, up, right).
.\" ----------
.TP
.B ^H
If the character cursor is not on the top line,
.I ^H
is the same as
.IR ^B .
.\" ----------
.TP
.B SPACE
If the character cursor is not on the top line,
the space bar is the same as
.IR ^F .
.\" ----------
.TP
.B TAB
If the character cursor is on the top line,
.SM TAB
starts a range (see below).
Otherwise, it is the same as
.IR ^F .
.\" ----------
.TP
.B "Arrow Keys"
The terminal's arrow keys provide another alternate set of cell cursor controls
if they exist and are supported in the appropriate
.I termcap
entry.
Some terminals have arrow keys which conflict with other control key codes.
For example, a terminal might send
.I ^H
when the back arrow key is pressed.
In these cases, the conflicting arrow key performs the same function
as the key combination it mimics.
.\" ----------
.TP
.B ^
Move the cell cursor up to row 0 of the current column.
.\" ----------
.TP
.B #
Move the cell cursor down to the last valid row of the current column.
.\" ----------
.TP
.B 0
Move the cell cursor backward to column A of the current row.
This command must be prefixed with
.I ^U
if quick numeric entry mode is enabled.
.\" ----------
.TP
.B $
Move the cell cursor forward to the last valid column of the current row.
.\" ----------
.TP
.B b
Scan the cursor backward (left and up) to the previous valid cell.
.\" ----------
.TP
.B w
Scan the cursor forward (right and down) to the next valid cell.
.\" ----------
.TP
.BI ^E d
Go to end of range.
Follow
.I ^E
by a direction indicator such as
.I ^P
or
.IR j .
If the cell cursor starts on a non-blank cell,
it goes in the indicated direction until the last non-blank adjacent cell.
If the cell cursor starts on a blank cell,
it goes in the indicated direction until the first non-blank cell.
This command is useful when specifying ranges of adjacent cells (see below),
especially when the range is bigger than the visible window.
.\" ----------
.TP
.B g
Go to a cell.
.I pname
prompts for a cell's name, a regular expression surrounded by
quotes, or a number.
If a cell's name such as
.I ae122 
or a the name of a defined range is given, the cell cursor goes
directly to that cell.
If a quoted regular expression such as "
.I Tax Table 
" or "
.I ^Jan [0-9]*$
" is given,
.I pname
searches for a cell containing a string matching the regular
expression.
See 
.I regex(3)
or
.I ed(1)
for more details on the form of regular
expressions.
If a number is given, 
.I pname
will search for a cell containing that number.
Searches for either strings or numbers proceed forward from the
current cell, wrapping back to a0 at the end of the table, and
terminate at the current cell if the string or number is not found.
The last
.I g
command is saved, and can be re-issued by entering 
.IR g<return> .
.\" ==========
.SS "Cell Entry and Editing Commands"
.\" ----------
Cells can contain both a numeric value and a string value.
Either value can be the result of an expression,
but not both at once,
i.e. each cell can have only one expression associated with it.
Entering a valid numeric expression
alters the cell's previous numeric value, if any,
and replaces the cell's previous string expression, if any,
leaving only the previously computed constant label string.
Likewise, entering a valid string expression
alters the cell's the previous label string, if any,
and replaces the cell's previous numeric expression, if any,
leaving only the previously computed constant numeric value.
.TP
.B =
Enter a numeric constant or expression into the current cell.
.I pname
prompts for the expression on the top line.
The usual way to enter a number into a cell is to type ``='',
then enter the number in response to the prompt on the top line.
The quick numeric entry option, enabled through the
.B \-n
option or
.I ^T
command, shows the prompt when you enter the first digit of a number
(you can skip typing ``='').
.\" ----------
.TP
.B <
Enter a label string into the current cell
to be flushed left against the left edge of the cell.
.\" ----------
.IP \fB"\fP
.PD 0
.TP
.B >
Enter a label string into the current cell
to be flushed right against the right edge of the cell.
.PD
.\" ----------
.PP
Strings you enter must start with ".
You can leave off the trailing " and
.I pname
will add it for you.
You can also enter a string expression
by backspacing over the opening " in the prompt.
.\" ----------
.TP
.B e
Edit the value associated with the current cell.
This is identical to ``=''
except that the command line starts out containing
the old numeric value or expression associated with the cell.
.\" ----------
.TP
.B E
Edit the string associated with the current cell.
This is identical to ``<'', ``"'', or ``>''
except that the command line starts out containing
the old string value or expression associated with the cell.
.\" ----------
.PP
To enter and edit a cell's number part, use the ``='' and
.I e
commands.
To enter and edit a cell's string part, use the ``<'', ``"'', ``>'', and
.I E
commands.
See the sections below on numeric and string expressions for more information.
.\" ----------
.TP
.B x
Clear the current cell.
Deletes the numeric value, label string, and/or numeric or string expression.
You can prefix this command with a count
of the number of cells on the current row to clear.  The current column is
used if column recalculation order is set.
Cells cleared with this command may be recalled
with any of the
.I pull
commands (see below).
.\" ----------
.TP
.B m
Mark a cell to be used as the source for the
.I copy
command.
.\" ----------
.TP
.B c
Copy the last marked cell to the current cell,
updating row and column references in its numeric or string expression, if any.
.\" ----------
.TP
.B +
If not in numeric mode, add the current numeric argument (default 1)
to the value of the current cell.  In numeric mode, ``+'' introduces a new
numeric expression or value, the same as ``=''. 
.\" ----------
.TP
.B -
If not in numeric mode, subtract the current numeric argument (default 1)
from the value of the current cell.  In numeric mode, ``-'' introduces a new,
negative, numeric expression or value, like ``=''. 
.\" ==========
.SS "File Commands"
.\" ----------
\0 \" exactly one blank line (hard to get)
.PD 0
.TP
.B G
Get a new database from a file.
If encryption is enabled,
the file is decrypted before it is loaded into the spreadsheet.
.PD
.\" ----------
.TP
.B P
Put the current database into a file.
If encryption is enabled,
the file is encrypted before it is saved.
.\" ----------
.TP
.B W
Write a listing of the current database into a file
in a form that matches its appearance on the screen.
This differs from the
.I Put
command in that its files are intended to be reloaded with
.IR Get ,
while
.I Write
produces a file for people to look at.  Hidden rows or columns
are not shown when the data is printed.
.\" ----------
.TP
.B T
Write a listing of the current database to a file,
but include delimiters suitable for processing by the
.IR tbl ,
.IR LaTeX ,
or
.I TeX
table processors.
The delimiters are controlled by the
.I tblstyle
option.  See
.I Set
above.
The delimters are are a colon\ (:) for style
.IR 0 or tbl
and an ampersand\ (&) for style
.IR latex or tex .
.\" ----------
.PP
With the
.IR Put ,
.IR Write ,
and
.I Table
commands, the optional range argument writes a subset of the spreadsheet to
the output file.
.\" ----------
.PP
With the
.I Write
and
.I Table
commands, if you try to write to the last file used with the
.I Get
or
.I Put
commands, or the file specified on the command line when
.I pname
was invoked, you are asked to confirm
that the (potentially) dangerous operation is really what you want.
.\" ----------
.PP
The three output commands,
.IR Put ,
.IR Write ,
and
.IR Table ,
can pipe their (unencrypted only) output to a program.
To use this feature,
enter ``| program'' to the prompt asking for a filename.
For example, to redirect the output of the
.I Write
command to the printer,
you might enter ``| lpr -p''.
.\" ----------
.TP
.B M
Merge the database from the named file into the current database.
Values and expressions defined in the named file
are read into the current spreadsheet
overwriting the existing entries at matching cell locations.
.\" ----------
.TP
.B R
Run macros.
Since
.I pname
files are saved as ASCII files,
it is possible to use them as primitive macro definition files.
The
.I Run
command makes this easier.
It's like the
.I Merge
command,
but prints a saved path name as the start of the filename to merge in.
The string to use is set with the
.I Define
command.
To write macros, you must be familiar with the file format written by the
.I Put
command.
This facility is still primitive and could be much improved.
.\" ----------
.TP
.B D
Define a path for the
.I Run
command to use.
.\" ----------
.PP
All file operations take a filename as the first argument
to the prompt on the top line.
The prompt supplies a " to aid in typing in the filename.
The filename can also be obtained from a cell's label string
or string expression.
In this case, delete the leading " with the backspace key
and enter a cell name such as
.I a22
instead.
If the resulting string starts with ``|'',
the rest of the string is interpreted as a
.SM UNIX
command, as above.
.\" ==========
.SS "Row and Column Commands"
.\" ----------
These commands can be used on either rows or columns.
The second letter of the command is either a row designator
(one of the characters
.IR r ,
.IR ^B ,
.IR ^F ,
.IR h ,
.IR l )
or a column designator (one of
.IR c ,
.IR ^P ,
.IR ^N ,
.IR k ,
.IR j ).
A small menu lists the choices for the second letter
when you type the first letter of one of these commands.
Commands which move or copy cells
also modify the row and column references in affected cell expressions.
The references may be frozen by using the
.I fixed
operator or using the
.I $
character in the reference to the cell (see below).
.\" ----------
.TP
.B "ir, ic"
Insert a new row (column)
by moving the row (column) containing the cell cursor,
and all following rows (columns), down (right) one row (column).
The new row (column) is empty.
.\" ----------
.TP
.B "ar, ac"
Append a new row (column) immediately following the current row (column).
It is initialized as a copy of the current one.
.\" ----------
.TP
.B "dr, dc"
Delete the current row (column).
.\" ----------
.TP
.B "pr, pc, pm"
Pull deleted rows (columns) back into the spreadsheet.
The last deleted set of cells is put back into the spreadsheet
at the current location.
.I pr
inserts enough rows to hold the data.
.I pc
inserts enough columns to hold the data.
.I pm
(merge) does not insert rows or columns;
it overwrites the cells beginning at the current cell cursor location.
.\" ----------
.TP
.B "vr, vc"
Remove expressions from the affected rows (columns),
leaving only the values which were in the cells
before the command was executed.
.\" ----------
.TP
.B "zr, zc"
Hide (``zap'') the current row (column).
This keeps a row (column) from being displayed but keeps it in the data base.
The status of the rows and columns is saved with the data base so hidden
rows and columns will be still
be hidden when you reload the spreadsheet.  Hidden rows or columns are not
printed by the
.I W
command.
.\" ----------
.TP
.B "sr, sc"
Show hidden rows (columns).
Enter a range of rows (columns) to be revealed.
The default is the first range of rows (columns) currently hidden.
This command ignores the repeat count, if any.
.\" ----------
.TP
.B f
Set the output format to be used
for printing the numeric values in each cell in the current column.
Enter two numbers:
the total width in characters of the column,
and the number of digits to follow decimal points.
Values are rounded off to the least significant digit displayed.
The total column width affects displays of strings as well as numbers.
A preceding count can be used to affect more than one column.
This command has only a column version (no second letter).
.\" ==========
.SS "Range Commands"
.\" ----------
Range operations affect a rectangular region on the screen
defined by the upper left and lower right cells in the region.
All of the commands in this class start with a slash;
the second letter of the command indicates which command.
A small menu lists the choices for the second letter when you type ``/''.
.I pname
prompts for needed parameters for each command.
Phrases surrounded by square brackets in the prompt are informational only
and may be erased with the backspace key.
.\" ----------
.PP
Prompts requesting variable names may be satisfied
with either an explicit variable name, such as
.IR A10 ,
or with a variable name previously defined in a
.I /d
command (see below).
Range name prompts require either an explicit range such as
.IR A10:B20 ,
or a range name previously defined with a
.I /d
command.
A default range shown in the second line
is used if you omit the range from the command or press the
.SM TAB
key (see below).
The default range can be changed by moving the cell cursor
via the control commands
.RI ( ^P ,
.IR ^N ,
.IR ^B ,
.IR ^F )
or the arrow keys.
The cells in the default range are highlighted
(using the terminal's standout mode, if available).
.\" ----------
.TP
.B /x
Clear a range.
Cells cleared with this command may be recalled with any of the
.I pull
commands.
.\" ----------
.TP
.B /v
Values only.
This command removes the expressions from a range of cells,
leaving just the values of the expressions.
.\" ----------
.TP
.B /c
Copy a source range to a destination range.
The source and destination may be different sizes.
The result is always one or more full copies of the source.
Copying a row to a row yields a row.
Copying a column to a column yields a column.
Copying a range to anything yields a range.
Copying a row to a column or a column to a row yields a range
with as many copies of the source as there are cells in the destination.
This command can be used to duplicate a cell through an arbitrary range
by making the source a single cell range such as
.IR b20:b20 .
.\" ----------
.TP
.B /f
Fill a range with constant values
starting with a given value and increasing by a given increment.
Each row is filled before moving on to the next row if row order
recalculation is set.  Column order fills each column in the range
before moving on to the next column.
The start and increment numbers may be positive or negative.
To fill all cells with the same value, give an increment of zero.
.\" ----------
.TP
.B /d
Use this command to assign a symbolic name to a single cell
or a rectangular range of cells on the screen.
The parameters are the name, surrounded by "",
and either a single cell name such as
.I A10
or a range such as
.IR a1:b20 .
Names defined in this fashion are used by the program in future prompts,
may be entered in response to prompts requesting a cell or range name,
and are saved when the spreadsheet is saved with the
.I Put
command.
Names defined must be more than two alpha characters long
to differentiate them from a column names,
and must not have embedded special characters.
Names may include the character ``_'' or numerals
as long as they occur after the first three alpha characters.
.\" ----------
.TP
.B /s
This command lists (shows) the currently defined range names.
If there are no defined range names, then a message is given,
otherwise
it pipes output to
.IR sort ,
then to
.IR less .
If the environment variable PAGER is set, its value is used in place of
.IR less.
.\" ----------
.TP
.B /u
Use this command to undefine a previously defined range name.
.\" ==========
.SS "Miscellaneous Commands"
.\" ----------
\0 \" exactly one blank line (hard to get)
.PD 0
.TP
.B Q
.TP
.B q
.TP
.B ^C
Exit from
.IR pname .
If you made any changes since the last
.I Get
or
.IR Put ,
.I pname
asks about saving your data before exiting.
.PD
.\" ----------
.TP
.B ^G
.PD 0
.TP
.B ESC
Abort entry of the current command.
.PD
.\" ----------
.TP
.B ?
Enter an interactive help facility.  Lets you look up brief
summaries of the main features of the program.  The help facility is
structured like this manual page so it is easy to find more
information on a particular topic.
.\" ----------
.TP
.B !
Shell escape.
.I pname
prompts for a shell command to run.
End the command line with the
.SM RETURN
key.
If the environment variable
.SM SHELL
is defined, that shell is run.
If not, /bin/sh is used.
Giving a null command line starts the shell in interactive mode.
A second ``!'' repeats the previous command.
.\" ----------
.TP
.B ^L
Redraw the screen.
.\" ----------
.TP
.B ^R
Redraw the screen with special highlighting of cells to be filled in.
This is useful for finding values you need to provide or update
in a form with which you aren't familiar
or of which you have forgotten the details.

It's also useful for checking a form you are creating.
All cells which contain constant numeric values
(not the result of a numeric expression)
are highlighted temporarily,
until the next screen change, however minor.
To avoid ambiguity,
the current range (if any) and current cell are not highlighted.
.\" ----------
.TP
.B ^X
This command is similar to
.IR ^R ,
but highlights cells which have expressions.
It also displays the expressions in the highlighted cells
as left-flushed strings,
instead of the numeric values and/or label strings of those cells.
This command makes it easier to check expressions,
at least when they fit in their cells or the following cell(s) are blank
so the expressions can slop over (like label strings).
In the latter case, the slop over is not cleared on the next screen update,
so you may want to type
.I ^L
after the
.I ^X
in order to clean up the screen.
.\" ----------
.TP
.B @
Recalculates the spreadsheet.
.\" ----------
.TP
.B ^V
Type, in the command line, the name of the current cell
(the one at the cell cursor).
This is useful when entering expressions
which refer to other cells in the table.
.\" ----------
.TP
.B ^W
Type, in the command line, the expression attached to the current cell.
If there is none, the result is ``?''.
.\" ----------
.TP
.B ^A
Type, in the command line, the numeric value of the current cell, if any.
.\" ----------
.PP
The
.IR ^V ,
.IR ^W ,
and
.I ^A
commands only work when the character cursor
is on the command line and beyond the first character.
.\" ----------
.TP
.B TAB
When the character cursor is on the top line,
defines a range of cells via the cursor control commands or the arrow keys.
The range is highlighted,
starts at the cell where you typed
.SM TAB,
and continues through the current cell cursor.
Pressing
.SM TAB
again causes the highlighted range to be entered into the command line
and the highlighting to be turned off.
This is most useful for defining ranges to functions such as
.IR @sum ().
Pressing ``)'' acts just like typing the
.SM TAB
key the second time and adds the closing ``)''.
Note that when you give a range command,
you don't need to press the first
.SM TAB
to begin defining a range starting with the current cell.
.\" ==========
.SS "Variable Names"
.\" ----------
Normally, a variable name is just the name of a cell, such as
.IR K20 .
The value is the numeric or string value of the cell,
according to context.
.\" ----------
.PP
When a cell's expression (formula) is copied to another location via
.I copy
or
.IR range-copy ,
variable references are by default offset by the amount the formula moved.
This allows the new formula to work on new data.
If cell references are not to change,
you can either use the
.I fixed
operator (see below),
or one of the following variations on the cell name.
.\" ----------
.TP
.I K20
References cell
.IR K20 ;
the reference changes when the formula is copied.
.\" ----------
.TP
.BI $ K $ 20
Always refers to cell
.IR K20 ;
the reference stays fixed when the formula is copied.
.\" ----------
.TP
.BI $ K20
Keeps the column fixed at column K;
the row is free to vary.
.\" ----------
.TP
.IB K $ 20
Similarly, this fixes the row and allows the column to vary.
.\" ----------
.PP
These conventions also hold on defined ranges.
Range references vary when formulas containing them are copied.
If the range is defined with fixed variable references,
the references do not change.
.\" ----------
.TP
.B fixed
To make a variable not change automatically when a cell moves,
put the word
.I fixed
in front of the reference, for example:
B1 \(** fixed C3.
.\" ==========
.SS "Numeric Expressions"
.\" ----------
Numeric expressions used with the ``=''
and
.I e
commands have a fairly conventional syntax.
Terms may be
constants,
variable names,
parenthesized expressions,
and negated terms.
Ranges may be operated upon with range functions such as sum
.RI ( @sum ())
and average
.RI ( @avg ()).
Terms may be combined using binary operators.
.\" ----------
.TP
.BR \- e
Negation.
.\" ----------
.TP
.RB e + e
Addition.
.\" ----------
.TP
.RB e \- e
Subtraction.
.\" ----------
.TP
.RB e \(** e
Multiplication.
.\" ----------
.TP
.RB e / e
Division.
.\" ----------
.TP
.RB e1 % e2
e1 mod e2.
.\" ----------
.TP
.RB e ^ e
Exponentiation.
.\" ----------
.TP
.RB e < e
.PD 0
.TP
.RB e <= e
.TP
.RB e = e
.TP
.RB e != e
.TP
.RB e >= e
.TP
.RB e > e
Relationals:
true (1) if and only if the indicated relation holds,
else false (0).
Note that ``<='', ``!='', and ``>=''
are converted to their ``~()'' equivalents.
.PD
.\" ----------
.TP
.BR ~ e
Boolean operator
.SM NOT.
.\" ----------
.TP
.RB e & e
Boolean operator
.SM AND.
.\" ----------
.TP
.RB e | e
Boolean operator
.SM OR.
.\" ----------
.TP
.RB e ? e : e
Conditional:
If the first expression is true then the value of the second is returned,
otherwise the value of the third.
.\" ----------
.PP
Operator precedence from highest to lowest is:
.PP
.nf
.RS
\-, ~
^
\(**, /
+, \-
<, <=, =, !=, >=, >
&
|
?:
.RE
.fi
.\" ==========
.SS "Built-in Range Functions"
.\" ----------
These functions return numeric values.
.\" ----------
.TP 18
.BR @sum (r)
Sum all valid (nonblank) entries in the region
whose two corners are defined by the two variable names (e.g.
.IR c5:e14 )
or the range name specified.
.\" ----------
.TP 18
.BR @prod (r)
Multiply together all valid (nonblank) entries in the specified region.
.\" ----------
.TP 18
.BR @avg (r)
Average all valid (nonblank) entries in the specified region.
.\" ----------
.TP 18
.BR @max (r)
Return the maximum value in the specified region.  See also the multi argument
version of
.I @max
below.
.\" ----------
.TP 18
.BR @min (r)
Return the minimum value in the specified region.  See also the multi argument
version of
.I @min
below.
.\" ----------
.TP 18
.BR @stddev (r)
Return the sample standard deviation of the cells in the specified region.
.\" ----------
.TP 18
.BR @lookup (e,r)
.PD 0
.TP 18
.BR @lookup (se,r)
.PD
Evaluates the expression then searches through the range
.I r
for a matching value.
The range should be either a single row or a single column.
The expression can be either a string
expression or a numeric expression.  If it is a numeric expression,
the range is searched for the the last value less than or equal to 
.IR e .
If the expression is a string expression, the string portions
of the cells in the range are searched for an exact string match.
The value returned is the numeric value from the next row and the same
column as the match, if the range was a single row, or the value from
the next column and the same row as the match if the range was a single
column.
.\" ----------
.TP 18
.BR @index (e,r)
Use the value of the expression 
.I e
to index into
the range
.IR r .
The numeric value at that position is returned. 
The value 1 selects the first item in the range,
2 selects the second item, etc.
.I R
should be either a single row or a single
column.
.\" ----------
.TP 18
.BR @stindex (e,r)
Use the value of 
.I e
to index into
the range
.IR r .
The string value at that position is returned. 
The value 1 selects the first item in the range,
2 selects the second item, etc.
The range should be either a single row or a single
column.
.\" ==========
.SS "Built-in Numeric Functions"
.\" ----------
All of these functions operate on floating point numbers (doubles)
and return numeric values.
Most of them are standard system functions more fully described in
.IR math (3).
The trig functions operate with angles in radians.
.\" ----------
.TP 18
.BR @sqrt (e)
Return the square root of
.IR e .
.\" ----------
.TP 18
.BR @exp (e)
Return the exponential function of
.IR e .
.\" ----------
.TP 18
.BR @ln (e)
Return the natural logarithm of
.IR e .
.\" ----------
.TP 18
.BR @log (e)
Return the base 10 logarithm of
.IR e .
.\" ----------
.TP 18
.BR @floor (e)
Return the largest integer not greater than
.IR e .
.\" ----------
.TP 18
.BR @ceil (e)
Return the smallest integer not less than
.IR e .
.\" ----------
.TP 18
.BR @rnd (e)
Round
.I e
to the nearest integer.
.\" ----------
.TP 18
.BR @fabs (e)
Return the absolute value of
.IR e .
.\" ----------
.TP 18
.BR @pow (e1,e2)
Return
.I e1
raised to the power of
.IR e2 .
.\" ----------
.TP 18
.BR @hypot (e1,e2)
Return sqrt(e1\(**e1+e2\(**e2), taking precautions against unwarranted
overflows.
.\" ----------
.TP 18
.B pi
A constant quite close to pi.
.\" ----------
.TP 18
.BR @dtr (e)
Convert
.I e
in degrees to radians.
.\" ----------
.TP 18
.BR @rtd (e)
Convert
.I e
in radians to degrees.
.\" ----------
.TP 18
.BR @sin (e)
.PD 0
.TP 18
.BR @cos (e)
.TP 18
.BR @tan (e)
Return trigonometric functions of radian arguments.
The magnitude of the arguments are not checked to assure meaningful results.
.PD
.\" ----------
.TP 18
.BR @asin (e)
Return the arc sine of
.I e
in the range -pi/2 to pi/2.
.\" ----------
.TP 18
.BR @acos (e)
Return the arc cosine of
.I e
in the range 0 to pi.
.\" ----------
.TP 18
.BR @atan (e)
Return the arc tangent of
.I e
in the range -pi/2 to pi/2.
.\" ----------
.TP 18
.BR @atan2 (e1,e2)
Returns the arc tangent of
.IR e1 / e2
in the range -pi to pi.
.\" ----------
.TP 18
.BR @max (e1,e2,...)
Return the maximum of the values of the expressions.  Two or more expressions
may be specified.  See also the range version of 
.I @max
above.
.\" ----------
.TP 18
.BR @min (e1,e2,...)
Return the minimum of the values of the expressions.  Two or more expressions
may be specified.  See also the range version of 
.I @min
above.
.\" ----------
.TP 18
.BR @ston (se)
Convert string expression
.I se
to a numeric value.
.\" ----------
.TP 18
.BR @eqs (se1,se2)
Return 1 if string expression
.I se1
has the same value as string expression
.IR se2 ,
0 otherwise.
.\" ----------
.TP 18
.BR @nval (se,e)
Return the numeric value of a cell selected by name.
String expression
.I se
must evaluate to a column name (``A''-``AE'') and
.I e
must evaluate to a row number (0-199). 
If
.I se
or
.I e
is out of bounds, or the cell has no numeric value, the result is 0.
You can use this for simple table lookups.
Be sure the table doesn't move unexpectedly!
See also
.IR @sval ()
below.
.\" ==========
.SS "String Expressions"
.\" ----------
String expressions are made up of constant strings
(characters surrounded by double quotation marks),
variables
(cell names, which refer to the cells's label strings or expressions),
and string functions.
Note that string expressions are only allowed
when entering a cell's label string, not its numeric part.
Also note that string expression results may be left or right flushed,
according to the type of the cell's string label.
.\" ----------
.TP
.B #
Concatenate strings.
For example, the string expression
.IP ""
	A0 # "zy dog"
.IP ""
displays the string ``the lazy dog'' in the cell if the value of
.IR A0 's
string is ``the la''.
.\" ==========
.SS "Built-in String Functions"
.\" ----------
\0 \" exactly one blank line (hard to get)
.PD 0
.TP 18
.BR @substr (se,e1,e2)
Extract and return from string expression
.I se
the substring indexed by character number
.I e1
through character number
.I e2
(defaults to the size of
.I se
if beyond the end of it).
If
.I e1
is less than 1 or greater than
.IR e2 ,
the result is the null string.
For example,
.PD
.IP ""
	@substr ("Nice jacket", 4, 7)
.IP ""
returns the string ``e jac''.
.\" ----------
.TP 18
.BR @fmt (se,e)
Convert a number to a string.
The argument
.I se
must be a valid
.IR printf (3)
format string.
.I e
is converted according to the standard rules.
For example, the expression
.IP ""
	@fmt ("\(**\(**%6.3f\(**\(**", 10.5)
.IP ""
yields the string ``\(**\(**10.500\(**\(**''.
.I e
is a double, so applicable formats are e, E, f, g, and G.
Try ``%g'' as a starting point.
.\" ----------
.TP 18
.BR @sval (se,e)
Return the string value of a cell selected by name.
String expression
.I se
must evaluate to a column name (``A''-``AE'') and
.I e
must evaluate to a row number (0-199). 
If
.I se
or
.I e
is out of bounds, or the cell has no string value,
the result is the null string.
You can use this for simple table lookups.
Be sure the table doesn't move unexpectedly!
.\" ----------
.TP 18
.BR @ext (se,e)
Call an external function (program or script).
The purpose is to allow arbitrary functions on values,
e.g. table lookups and interpolations.
String expression
.I se
is a command or command line to call with
.IR popen (3).
The value of
.I e
is converted to a string and appended to the command line as an argument.
The result of
.IR @ext ()
is a string:
the first line printed to standard output by the command.
The command should emit exactly one output line.
Additional output, or output to standard error, messes up the screen.
.IR @ext ()
returns a null string and prints an appropriate warning
if external functions are disabled,
.I se
is null, or the attempt to run the command fails.
.IP ""
External functions can be slow to run,
and if enabled are called at each screen update,
so they are disabled by default.
You can enable them with
.I ^T
when you really want them called.
.IP ""
A simple example:
.IP ""
	@ext ("echo", a1)
.IP ""
You can use
.IR @ston ()
to convert the
.IR @ext ()
result back to a number.
For example:
.IP ""
	@ston (@ext ("form.sc.ext", a9 + b9))
.IP ""
Note that you can built a command line (including more argument values)
from a string expression with concatenation.
You can also "hide" the second argument by ending the command line
(first argument) with `` #'' (shell comment).
.\" ==========
.SS "Built-in Financial Functions"
.\" ----------
Financial functions compute the mortgage (or loan) payment, future value,
and the present value functions.  Each accepts
three arguments, an amount, a rate of interest (per period), and 
the number of periods.
These functions are the same as those commonly found in other spreadsheets
and financial calculators
.\" ----------
.TP 18
.BR @pmt (e1,e2,e3)
.IR @pmt (60000,.01,360)
computes the monthly payments for a $60000 mortgage at 12% annual interest
(.01 per month) for 30 years (360 months).
.\" ----------
.TP 18
.BR @fv (e1,e2,e3)
.IR @fv (100,.005,36)
computes the future value for of 36 monthly payments of $100 at 6% 
interest (.005 per month).  It answers the question: "How much
will I have in 2 years if I deposit $100 per month in a savings account paying
6% interest compounded monthly?"
.\" ----------
.TP 18
.BR @pv (e1,e2,e3)
.IR @pv (1000,.015,36)
computes the present value of an a ordinary annuity of
36 monthly payments of $1000 at 18% annual interest.
It answers the question: "How much can I borrow at 18% for 30 years
if I pay $1000 per month?"
.\" ==========
.SS "Built-in Date and Time Functions"
.\" ----------
Time for
.I pname
follows the system standard:
the number of seconds since 1970.
All date and time functions except
.IR @date ()
return numbers, not strings.
.\" ----------
.TP 18
.B @now
Return the current time encoded
as the number of seconds since December 31, 1969, midnight, GMT.
.\" ----------
.PP
The following functions take the time in seconds
(e.g. from
.IR @now )
as an argument and return the specified value.
The functions all convert from GMT to local time.
.\" ----------
.TP 18
.BR @date (e)
Convert the time in seconds to a date string
24 characters long in the following form:
.IP ""
.I "	Sun Sep 16 01:03:52 1973"
.IP ""
Note that you can extract parts of this fixed-format string with
.IR @substr ().
.\" ----------
.TP 18
.BR @year (e)
Return the year.
Valid years begin with 1970.
The last legal year is system dependent.
.\" ----------
.TP 18
.BR @month (e)
Return the month, encoded as 1 (January) to 12 (December).
.\" ----------
.TP 18
.BR @day (e)
Return the day of the month, encoded as 1 to 31.
.\" ----------
.TP 18
.BR @hour (e)
Return the number of hours since midnight, encoded as 0 to 23.
.\" ----------
.TP 18
.BR @minute (e)
Return the number of minutes since the last full hour, encoded as 0 to 59.
.\" ----------
.TP 18
.BR @second (e)
Return the number of seconds since the last full minute, encoded as 0 to 59.
.\" ==========
.SS "Spreadsheet Update"
.\" ----------
Re-evaluation of spreadsheet expressions
is done by row or by column depending on the selected calculation order.
Evaluation is repeated up to 
.I iterations
times for each update if necessary,
so forward references usually work as expected.  See
.I set
above.
If stability is not reached after ten iterations,
a warning is printed.
This is usually due to a long series of forward references,
or to unstable cyclic references (for example, set
.IR A0 's
expression to ``A0+1'').
.\" ==========
.SH SEE ALSO
bc(1), dc(1), crypt(1), ppname(1)
.\" ==========
.SH BUGS
Top-to-bottom, left-to-right evaluation of expressions is silly.
A proper following of the dependency graph
with (perhaps) recourse to relaxation should be implemented.
.\" ----------
.PP
Supports at most 200 rows and 40 columns.
.\" ----------
.PP
Editing is crude.
All you can do is backspace over and retype text to be altered.
There is no easy way to switch a leftstring to a rightstring or vice versa.
Of course, you can always write the spreadsheet to a file with
.IR Put ,
edit it by calling an editor on the file with ``!'',
and read it back with
.I Get
-- if you are comfortable editing spreadsheet files.
.\" ----------
.PP
Only one previous value is saved from any call of
.IR @ext ().
If it is used more than once in a spreadsheet
and external functions are enabled and later disabled,
the last returned value pops up in several places.
.\" ----------
.PP
On some systems,
if the cell cursor is in column 0 with topline enabled
(so the current cell is highlighted),
or if any cell in column 0 is highlighted,
the corresponding row number gets displayed and then blanked
during a screen refresh.
This looks like a bug in
.IR curses .
.\" ----------
.PP
Many commands give no indication (a message or beep) if they have null effect.
Some should give confirmation of their action, but they don't.

Added doc/tutorial.sc.

































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# This data file was generated by the Spreadsheet Calculator.
# You almost certainly shouldn't edit it.

define "page4" A70
define "page3" A49
define "page2" A29
define "page1" A9
define "page5" A89
leftstring A1 = "This is a brief sc tutorial."
leftstring A3 = "Cells are named by their column and row number.  For example,"
leftstring A4 = "Cell A4"
leftstring B4 = "Cell B4"
leftstring C4 = "Cell C4"
leftstring A5 = "Cell A5"
leftstring A6 = "Cell A6"
leftstring C6 = "Cell C6"
leftstring A7 = "Cells range from A0 to AN199."
leftstring A8 = "Cells can also be named by the user.  See 'range names' in the manual."
leftstring page1 = "You can move the cursor a couple of different ways:"
leftstring A11 = "^n, j and the <DOWN> arrow key go down"
leftstring A12 = "^p, k and the <UP> arrow key go up"
leftstring A13 = "^b, h and the <LEFT> arrow key go left"
leftstring A14 = "^f, l and the <RIGHT> arrow key go right"
leftstring A15 = "You can go directly to a cell by typing 'g' and the cell name. "
leftstring A16 = "'g c6' will take you to cell c6."
leftstring A18 = "Cells can contain numbers, formulas, or text."
leftstring A19 = "Most of the cells on this page contain text."
leftstring C20 = "<Type 'g page2' to continue>"
leftstring A22 = "Cell d22 contains text"
leftstring D22 = "Text "
leftstring A23 = "Cell d23 contains a number"
let D23 = 123.34
leftstring A24 = "Cell d24 contains a formula"
let D24 = D23+88
leftstring A26 = "To see what the cell contains, just move the cursor"
leftstring A27 = "onto the cell.  The contents will show up on line 1 in the brackets."
leftstring page2 = "You can enter data into cells like this:"
leftstring B30 = "'<text' enters left justified text."
leftstring B31 = "'>text' enters right justified text."
leftstring B32 = "'=number' enters a number"
leftstring B33 = "'=formula' enters a formula."
leftstring A35 = "Try duplicating d22 through d24 in e22 though e24."
leftstring A37 = "You erase a cell by typing 'x' with the cursor on the cell."
leftstring C40 = "<Type 'g page3' to continue>"
leftstring A42 = "Here is a typical use for numbers and formulas:"
let A44 = 10.3
let B44 = 1877.5
let C44 = 234.7
let E44 = @sum(A44:C44)
let A45 = 44.56
let B45 = 44.3
let C45 = -3
let E45 = @sum(A45:C45)
let A46 = 88.74
let B46 = 8000
let C46 = -9
let E46 = @sum(A46:C46)
let A47 = 99.2
let B47 = -88
let C47 = -44.6
let E47 = @sum(A47:C47)
let page3 = @sum(A44:A47)
let B49 = @sum(B44:B47)
let C49 = @sum(C44:C47)
let E49 = @sum(A44:C47)
leftstring A51 = "The data is entered in a44 through c47."
leftstring A52 = "Cells a49, b49 and c49 sum their respective columns."
leftstring A53 = "Cells e44, e45, e46, and e47 sum their respective rows."
leftstring A54 = "Cell E49 is a grand total."
leftstring A55 = "Try changing some of the data cells and watch the sums change."
leftstring A57 = "You can also edit cells by putting the cursor on the cell and typing:"
leftstring B58 = "'e' to edit the numeric portion."
leftstring B59 = "'E' to edit the string portion."
leftstring C60 = "<Type 'g page4' to continue>"
leftstring A62 = "Since you are reading this, you know that you can load "
leftstring A63 = "a data base from a file by typing the file name as an"
leftstring A64 = "argument to the program.  You can also load or save a "
leftstring A65 = "data base using the file commands:"
leftstring B67 = "'G file'"
leftstring C67 = "Gets the data from an sc file."
leftstring B68 = "'P file'"
leftstring C68 = "Puts the data from the spreadsheet into a file."
leftstring page4 = "Try 'P foo.sc' to write this to the file foo.sc"
leftstring A71 = "The Get command erases the current spreadsheet.  "
leftstring A72 = "To merge a spreadsheet with the one currently in"
leftstring A73 = "the machine, use:"
leftstring B75 = "'M file'"
leftstring C75 = "Merge the data from a saved sc file."
leftstring A77 = "You can also get human readable versions of the data"
leftstring A78 = "by using the Write command:"
leftstring C80 = "<Type 'g page5' to continue>"
leftstring A82 = "Try 'W tut.txt' for a clear text version of the tutorial."
leftstring A85 = "This is the end of the tutorial.  We have explored"
leftstring A86 = "The basic commands.  Much more detail is available"
leftstring A87 = "in the man page."
leftstring D91 = "GOOD LUCK!"

Added doc/vms_note.















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
From: ihnp4!gargoyle!oddjob!noao!arizona!naucse!jdc (John Campbell)
To: arizona!noao!oddjob!gargoyle!ihnp4!nsc!nscpdc!rgb
Subject: VMS SC

VMS USERS:

Bob Bond has been generous enough to give me free rein in adding what I
think is needed to make SC run on VMS.  Any problems with VMS should be
directed to me--they are not Bob's fault.

The VMS SC is "SIMPLE" for the most part, except that the arrow keys
(instead of hjkl) will move you around the cells.  The VMS version of SC
will not interact with the Bourne shell (obviously), which means that CRYPT
and EXTERNAL FUNCTIONS will not be available.

If you have a 'C' compiler and GNU Bison then you should be able to get
SC running on VMS by following the instructions below.

Step 1:  Get all the files

I've heard of a few sites that can unpack unix shar files directly on
VMS.  Most people, however, will need access to a unix machine to get
the original distribution unpacked.  At this time you should also build
experres.h and statres.h and perhaps run the man pages off if you need
to port the documentation. To build the two "missing" hearder files:
   sed <gram.y >experres.h -f eres.sed
   sed <gram.y >statres.h -f sres.sed

Step 2: Cut out BUILD.COM and GETOPT.C

At the end of this file are two other pieces: BUILD.COM and GETOPT.C.  After
you've moved everything to VMS, cut BUILD.COM and GETOPT.C out of here and
put them in the same directory as the rest of the SC distribution.

Step 3: Build it

Theoretically all you now need to do is @BUILD and SC (as well as PSC)
will be running on VMS.  If you have problems feel free to contact me
at ...!arizona!naucse!jdc  (or even call at 602-523-6259).

---------------------cut here for BUILD.COM--------------------------
$! VMS command file to build SC and PSC (requires bison)
$! SC:
$ bison -d gram.y
$ ren gram_tab.c gram.c
$ cc  /define=("SIMPLE","SIGVOID") sc.c
$ cc  /define=("SIMPLE","SIGVOID") gram.c
$ cc  /define=("SIMPLE","SIGVOID") lex.c
$ cc  /define=("SIMPLE","SIGVOID") interp
$ cc  /define=("SIMPLE","SIGVOID") cmds
$ cc  /define=("SIMPLE","SIGVOID") xmalloc
$ cc  /define=("SIMPLE","SIGVOID") range
$ cc  /define=("SIMPLE","SIGVOID") help
$ link sc.obj,lex.obj,gram.obj,interp.obj,cmds.obj,xmalloc.obj,-
       range.obj,help.obj,sys$library:vaxcrtl.olb/lib
$ !
$ ! Create VMS foreign command symbol to test SC
$ !
$ sc == "$" + f$logical("SYS$DISK") + f$directory() + "SC.EXE"
$!
$! Now PSC
$!
$ cc psc.c
$ cc getopt.c
$ link psc,getopt,sys$library:vaxcrtl.olb/lib
$ !
$ ! Create VMS foreign command symbol to test PSC (Note that
$ ! PSC reads SYS$INPUT and writes to SYS$OUTPUT, so use
$ ! DEFINE/USER to redirect.)
$ !
$ psc == "$" + f$logical("SYS$DISK") + f$directory() + "PSC.EXE"

---------------------cut here for GETOPT.C------------------------
/*
 * getopt - get option letter from argv
 *      This software is in the public domain
 *      Originally written by Henry Spencer at the U. of Toronto
 */

#include <stdio.h>

char    *optarg;        /* Global argument pointer. */
int     optind = 0;     /* Global argv index. */

static char     *scan = NULL;   /* Private scan pointer. */

/* extern char     *index();  obsolete, used strchr (JDC). */

int
getopt(argc, argv, optstring)
int argc;
char *argv[];
char *optstring;
{
        register char c;
        register char *place;

        optarg = NULL;

        if (scan == NULL || *scan == '\0') {
                if (optind == 0)
                        optind++;

                if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
                        return(EOF);
                if (strcmp(argv[optind], "--")==0) {
                        optind++;
                        return(EOF);
                }

                scan = argv[optind]+1;
                optind++;
        }

        c = *scan++;
        place = strchr(optstring, c);

        if (place == NULL || c == ':') {
                fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
                return('?');
        }

        place++;
        if (*place == ':') {
                if (*scan != '\0') {
                        optarg = scan;
                        scan = NULL;
                } else {
                        optarg = argv[optind];
                        optind++;
                }
        }

        return(c);
}

Added experres.h.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
	"FIXED",	K_FIXED,
	"SUM",	K_SUM,
	"PROD",	K_PROD,
	"AVG",	K_AVG,
	"STDDEV",	K_STDDEV,
	"ACOS",	K_ACOS,
	"ASIN",	K_ASIN,
	"ATAN",	K_ATAN,
	"ATAN2",	K_ATAN2,
	"CEIL",	K_CEIL,
	"COS",	K_COS,
	"EXP",	K_EXP,
	"FABS",	K_FABS,
	"FLOOR",	K_FLOOR,
	"HYPOT",	K_HYPOT,
	"LN",	K_LN,
	"LOG",	K_LOG,
	"PI",	K_PI,
	"POW",	K_POW,
	"SIN",	K_SIN,
	"SQRT",	K_SQRT,
	"TAN",	K_TAN,
	"DTR",	K_DTR,
	"RTD",	K_RTD,
	"MAX",	K_MAX,
	"MIN",	K_MIN,
	"RND",	K_RND,
	"PV",	K_PV,
	"FV",	K_FV,
	"PMT",	K_PMT,
	"HOUR",	K_HOUR,
	"MINUTE",	K_MINUTE,
	"SECOND",	K_SECOND,
	"MONTH",	K_MONTH,
	"DAY",	K_DAY,
	"YEAR",	K_YEAR,
	"NOW",	K_NOW,
	"DATE",	K_DATE,
	"FMT",	K_FMT,
	"SUBSTR",	K_SUBSTR,
	"STON",	K_STON,
	"EQS",	K_EQS,
	"EXT",	K_EXT,
	"NVAL",	K_NVAL,
	"SVAL",	K_SVAL,
	"LOOKUP",	K_LOOKUP,
	"STLOOKUP",	K_STLOOKUP,
	"INDEX",	K_INDEX,
	"STINDEX",	K_STINDEX,
	"AUTO",	K_AUTO,
	"AUTOCALC",	K_AUTOCALC,
	"BYROWS",	K_BYROWS,
	"BYCOLS",	K_BYCOLS,
	"BYGRAPH",	K_BYGRAPH,
	"ITERATIONS",	K_ITERATIONS,
	"NUMERIC",	K_NUMERIC,
	"PRESCALE",	K_PRESCALE,
	"EXTFUN",	K_EXTFUN,
	"CELLCUR",	K_CELLCUR,
	"TOPROW",	K_TOPROW,
	"TBLSTYLE",	K_TBLSTYLE,
	"TBL",	K_TBL,
	"LATEX",	K_LATEX,
	"TEX",	K_TEX,

Added gram.c.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
#ifndef lint
static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
#endif
#define YYBYACC 1
#define YYMAJOR 1
#define YYMINOR 9
#define yyclearin (yychar=(-1))
#define yyerrok (yyerrflag=0)
#define YYRECOVERING (yyerrflag!=0)
#define YYPREFIX "yy"
#line 20 "gram.y"
#include <curses.h>
#include "sc.h"

#define ENULL (struct enode *)0

char *strcpy();
#line 28 "gram.y"
typedef union {
    int ival;
    double fval;
    struct ent_ptr ent;
    struct enode *enode;
    char *sval;
    struct range_s rval;
} YYSTYPE;
#line 28 "y.tab.c"
#define STRING 257
#define NUMBER 258
#define FNUMBER 259
#define RANGE 260
#define VAR 261
#define WORD 262
#define COL 263
#define S_FORMAT 264
#define S_LABEL 265
#define S_LEFTSTRING 266
#define S_RIGHTSTRING 267
#define S_GET 268
#define S_PUT 269
#define S_MERGE 270
#define S_LET 271
#define S_WRITE 272
#define S_TBL 273
#define S_COPY 274
#define S_SHOW 275
#define S_ERASE 276
#define S_FILL 277
#define S_GOTO 278
#define S_DEFINE 279
#define S_UNDEFINE 280
#define S_VALUE 281
#define S_MDIR 282
#define S_HIDE 283
#define S_SET 284
#define K_FIXED 285
#define K_SUM 286
#define K_PROD 287
#define K_AVG 288
#define K_STDDEV 289
#define K_ACOS 290
#define K_ASIN 291
#define K_ATAN 292
#define K_ATAN2 293
#define K_CEIL 294
#define K_COS 295
#define K_EXP 296
#define K_FABS 297
#define K_FLOOR 298
#define K_HYPOT 299
#define K_LN 300
#define K_LOG 301
#define K_PI 302
#define K_POW 303
#define K_SIN 304
#define K_SQRT 305
#define K_TAN 306
#define K_DTR 307
#define K_RTD 308
#define K_MAX 309
#define K_MIN 310
#define K_RND 311
#define K_PV 312
#define K_FV 313
#define K_PMT 314
#define K_HOUR 315
#define K_MINUTE 316
#define K_SECOND 317
#define K_MONTH 318
#define K_DAY 319
#define K_YEAR 320
#define K_NOW 321
#define K_DATE 322
#define K_FMT 323
#define K_SUBSTR 324
#define K_STON 325
#define K_EQS 326
#define K_EXT 327
#define K_NVAL 328
#define K_SVAL 329
#define K_LOOKUP 330
#define K_STLOOKUP 331
#define K_INDEX 332
#define K_STINDEX 333
#define K_AUTO 334
#define K_AUTOCALC 335
#define K_BYROWS 336
#define K_BYCOLS 337
#define K_BYGRAPH 338
#define K_ITERATIONS 339
#define K_NUMERIC 340
#define K_PRESCALE 341
#define K_EXTFUN 342
#define K_CELLCUR 343
#define K_TOPROW 344
#define K_TBLSTYLE 345
#define K_TBL 346
#define K_LATEX 347
#define K_TEX 348
#define YYERRCODE 256
short yylhs[] = {                                        -1,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    7,    7,    7,
    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
    7,    7,    7,    7,    7,    7,    7,    7,    7,    6,
    6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
    6,    6,    6,    6,    6,    6,    8,    8,    3,    3,
    1,    1,    1,    1,    1,    4,    4,    2,    2,    2,
    2,    5,    5,    9,    9,   10,   10,   10,   10,   10,
   10,   10,   10,   10,   10,   10,   10,   10,   10,   10,
   10,   10,   10,   10,   10,   10,   10,   10,   10,
};
short yylen[] = {                                         2,
    4,    4,    4,    4,    6,    4,    2,    2,    2,    3,
    2,    3,    2,    3,    2,    4,    4,    2,    2,    3,
    1,    2,    1,    2,    3,    4,    2,    2,    2,    1,
    2,    3,    3,    2,    2,    0,    1,    1,    2,    5,
    5,    5,    5,    5,    7,    5,    7,    5,    5,    5,
    7,    5,    5,    5,    5,    5,    7,    5,    5,    7,
    5,    5,    5,    5,    5,    5,    9,    9,    9,    5,
    5,    5,    5,    5,    5,    2,    5,    7,    5,    7,
    7,    7,    9,    7,    9,    7,    7,    7,    7,    9,
    3,    2,    2,    1,    1,    1,    1,    2,    2,    3,
    3,    3,    3,    3,    3,    1,    5,    3,    3,    3,
    3,    3,    4,    4,    4,    3,    1,    3,    3,    1,
    2,    3,    3,    4,    1,    1,    1,    1,    1,    2,
    2,    1,    1,    0,    2,    1,    1,    2,    2,    2,
    2,    1,    1,    1,    1,    2,    1,    2,    1,    2,
    1,    2,    1,    2,    3,    3,    3,    3,    3,
};
short yydefred[] = {                                      0,
   37,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,  134,    0,    0,  120,  125,    0,    0,    0,  126,
    0,    0,    0,  132,  133,    7,    0,    8,    0,    0,
    0,    0,    0,    0,    0,   22,  128,  129,    0,    0,
    0,    0,   29,   28,   27,    0,   34,   24,    9,   19,
   18,    0,    0,    0,  121,    0,    0,    0,    0,    0,
    0,   10,    0,   12,   14,   20,    0,    0,  131,  130,
   25,    0,    0,   32,  136,  137,  143,  142,  144,    0,
  145,  147,  149,  151,  153,    0,    0,    0,  135,    6,
    0,  123,  122,    0,  119,   97,   94,   95,    0,   96,
    0,    0,    0,    0,    0,    0,   38,    0,  106,    0,
    0,    0,   17,   16,   26,    0,    0,  140,  141,  146,
  148,  150,  152,  154,  138,  139,    0,  124,   39,   99,
   92,   93,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,   76,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
   98,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,  155,  156,  157,  158,  159,
    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,   91,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,  105,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,   40,   41,   42,
   43,   48,   49,   50,    0,   52,   53,   54,   55,   56,
    0,   58,   59,    0,   61,   62,   63,   64,   65,   44,
    0,   46,    0,   66,    0,    0,    0,   70,   71,   72,
   73,   74,   75,   79,    0,    0,   77,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,   51,   57,   60,   45,    0,
   47,    0,    0,    0,   80,    0,   78,   87,   88,   89,
   82,    0,   84,    0,   81,   86,    0,    0,    0,    0,
    0,    0,    0,   67,   68,   69,   90,   83,   85,
};
short yydgoto[] = {                                      23,
  117,   51,   30,   31,   36,  380,  119,  381,   62,   99,
};
short yysindex[] = {                                   2807,
    0, -214,  -26,  -26,  -26,   -5,   -5,   -5,  -26,   -5,
   -5,  -26, -181,  -26,  178,   87,   -5,  -26,  -26,   -5,
 -164,    0,    0,  -16,    0,    0,    5, -189,   20,    0,
   23,   27,   29,    0,    0,    0,  -26,    0,   31,  -26,
  -26,   20,  -26,   42,   56,    0,    0,    0,   18,   18,
   18,   18,    0,    0,    0,  -26,    0,    0,    0,    0,
    0,   -8, -160, -153,    0, -137,    9,  -10,  214,  214,
  214,    0,  214,    0,    0,    0, -124, -128,    0,    0,
    0,   18,   20,    0,    0,    0,    0,    0,    0,   79,
    0,    0,    0,    0,    0,   80,   39, -276,    0,    0,
 -109,    0,    0, -101,    0,    0,    0,    0,  214,    0,
  214,  214,  214, 2729,  214,  214,    0, 2841,    0, 2841,
 2841, 2841,    0,    0,    0, -100, -231,    0,    0,    0,
    0,    0,    0,    0,    0,    0,  -99,    0,    0,    0,
    0,    0,  120,  121,  122,  123,  124,  125,  175,  177,
  179,  180,  182,  184,  185,  190,  193,  196,  198,  199,
  200,  201,  203,  204,  205,  206,  215,  231,  233,  239,
  240,  241,  242,  243,  244,  245,    0,  247,  249,  251,
  262,  264,  272,  274,  275,  278,  283,  284,  298,  671,
    0,  214,  214,  214,    3,  214,   11,  280,  214,  214,
  214,  214,  214,  214,  214,    0,    0,    0,    0,    0,
    0,  -26,  -26,  -26,  -26,  214,  214,  214,  214,  214,
  214,  214,  214,  214,  214,  214,  214,  214,  214,  214,
  214,  214,  214,   40,   40,  214,  214,  214,  214,  214,
  214,  214,  214,  214,  214,  214,  214,  214,  214,  214,
  214,  214,  214,  214,  214,  214,  214,    0,  706, 2907,
 2937,  214,   44,   44,  214,   44,  214,   13,   13,   13,
  255,  255,  255,    0,  302,  311,  315,  318,  741,  776,
  811,  846,  881,  916,  951,  986, 1021, 1056, 1091, 1126,
 1161, 1196, 1231, 1266, 1301, 1336,   20,  319, 1371,  320,
 1406, 1441, 1476, 1511, 1546, 1581, 1616, 1651, 1686, 1721,
 1756, 1791, 1826, 1861, 1896, 1931, 1966, 2001, 2036, 2071,
 2106, 2141, 2176,  214,   44,   44,   44,    0,    0,    0,
    0,    0,    0,    0,  214,    0,    0,    0,    0,    0,
  214,    0,    0,  214,    0,    0,    0,    0,    0,    0,
  214,    0,  214,    0,  214,  214,  214,    0,    0,    0,
    0,    0,    0,    0,  214,  214,    0,  214,  214,  214,
  214,  -26,  -26,  -26,  -26, 2872, 2211, 2246, 2281, 2841,
   61,   67, 2316, 2351, 2386, 2421, 2456, 2491, 2526, 2561,
 2596,   68,   78,  321,  323,    0,    0,    0,    0,  214,
    0,  214,  214,  214,    0,  214,    0,    0,    0,    0,
    0,  214,    0,  214,    0,    0, 2841, 2631, 2666, 2701,
 2736, 2771, 2806,    0,    0,    0,    0,    0,    0,
};
short yyrindex[] = {                                    339,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,  366,    0,  375,    0,    0,  376,    0,
    0,    0,    0,    0,    0,    0,    0,    0,   52,    0,
    0,    0,    0,    0,    0,    0,  377,    0,    0,  378,
  384,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,  385,    0,    0,    0,    0,
    0,  390,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,  392,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,  394,    0,  397,
  398,  404,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,  367,
  368,    0,  547,  548,    0,  575,    0,  474,  508,  539,
  358,  407,  443,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,  632,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,  576,  587,  603,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,   62,    0,    0,    0,   92,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,   98,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,
};
short yygindex[] = {                                      0,
   -3,   19,  253,   14,  503,  -49,   15,   57,    0,    0,
};
#define YYTABLESIZE 3091
short yytable[] = {                                      29,
   29,   29,   35,   35,   35,   29,   35,   35,   42,   28,
   29,   29,   29,   35,   29,   29,   35,   32,   33,  118,
  120,  121,   39,  122,   97,   28,  207,   46,   52,   55,
   28,   57,   58,   42,   54,  111,   42,   42,   28,   29,
   66,   64,  115,  111,  104,  112,   28,  113,   24,  204,
  115,  127,   83,  112,  202,  113,   76,  135,  136,  203,
   49,  107,   50,  262,  105,  190,  114,   79,   80,   81,
   82,  265,  111,   67,  114,   28,   44,   68,  201,  115,
  204,   45,  112,   69,  113,  202,  199,   70,  200,   71,
  203,   73,  127,   60,  127,  127,  127,  100,   61,   77,
  125,  399,  107,  114,  400,  107,  205,  401,  411,  101,
  400,  412,  127,   78,  208,  209,  210,   98,  413,  107,
  102,  414,   28,  139,  107,  140,  141,  142,  116,   49,
  191,   50,  117,  123,  124,  117,  116,  205,  118,  126,
  127,  118,  259,  260,  261,  263,  264,  266,  137,  268,
  269,  270,  271,  272,  273,  274,  138,  206,  211,  212,
  213,  214,  215,  216,  217,  116,  279,  280,  281,  282,
  283,  284,  285,  286,  287,  288,  289,  290,  291,  292,
  293,  294,  295,  296,  299,  301,  302,  303,  304,  305,
  306,  307,  308,  309,  310,  311,  312,  313,  314,  315,
  316,  317,  318,  319,  320,  321,  322,  323,   29,   29,
   29,   29,  325,   28,  218,  326,  219,  327,  220,  221,
   49,  222,   50,  223,  224,  275,  276,  277,  278,  225,
  297,  297,  226,   25,   26,  227,   27,  228,  229,  230,
  231,   63,  232,  233,  234,  235,  111,  298,  300,   28,
   26,   34,   27,  115,  236,   26,  112,   27,  113,  106,
  107,  108,   65,   26,   43,   27,  103,  106,  107,  108,
  237,   26,  238,   27,  376,   47,   48,  114,  239,  240,
  241,  242,  243,  244,  245,  377,  246,  109,  247,   72,
  248,  378,   74,   75,  379,  109,  106,  107,  108,   25,
   26,  249,   27,  250,  110,  383,  384,  385,   84,  127,
  127,  251,  110,  252,  253,  386,  387,  254,  388,  389,
  390,  391,  255,  256,  109,   85,   86,   87,   88,   89,
   90,   91,   92,   93,   94,   95,   96,  257,   36,  116,
  267,  110,  328,   53,   47,   48,   25,   26,  205,   27,
  417,  329,  418,  419,  420,  330,  421,  102,  331,  350,
  352,  415,  422,  416,  423,   21,  112,  111,   29,   29,
   29,   29,  128,  129,   30,   23,   11,   13,  130,  131,
  132,  133,  134,   15,   31,  392,  393,  394,  395,   35,
  102,   33,  102,    2,  102,  102,    3,    4,  102,  102,
  102,  102,  102,    1,  102,  111,  103,  112,  111,  382,
  112,  111,    0,    0,    0,  102,    0,  102,  102,  102,
  102,    0,    0,    0,  112,  111,    0,    0,    0,  112,
  111,    0,    0,    0,    0,   47,   48,   25,   26,  103,
   27,  103,  104,  103,  103,    0,    0,  103,  103,  103,
  103,  103,    0,  103,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,  103,    0,  103,  103,  103,  103,
  106,  107,  108,  100,   26,  104,   27,  104,    0,  104,
  104,  102,    0,  104,  104,  104,  104,  104,    0,  104,
  112,  111,    0,    0,    0,    0,    0,    0,  109,    0,
  104,    0,  104,  104,  104,  104,  100,  101,  100,   37,
   38,  100,   40,   41,  100,  110,  100,  100,  100,   56,
    0,    0,   59,    0,    0,    0,    0,    0,    0,    0,
  103,  100,    0,  100,  100,  100,  100,    0,  116,    0,
  101,    0,  101,    0,    0,  101,  108,  109,  101,    0,
  101,  101,  101,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,  101,  104,  101,  101,  101,
  101,  116,    0,  116,  110,  113,  116,    0,    0,  116,
    0,  116,  116,  116,  108,  109,  115,  108,  109,    0,
  108,  109,    0,    0,    0,    0,  116,  100,  116,  116,
  116,  116,  114,    0,  108,  109,    0,    0,    0,  108,
  109,    0,  110,  113,    0,  110,  113,    0,  110,  113,
    0,    0,    0,    0,  115,    0,    0,  115,    0,    0,
  115,  101,  110,  113,    0,    0,    0,  110,  113,    0,
  114,    0,    0,  114,  115,    0,  114,    0,    0,  115,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
  114,    0,  116,    0,   38,  114,   38,    0,   38,   38,
  108,  109,  127,   38,   38,   38,   38,    0,   38,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,   38,   38,   38,   38,    0,    0,    0,  110,  113,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
  115,  258,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,    0,   38,  114,    0,    0,    0,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,    0,
  200,    0,  203,    0,    0,   38,    0,    0,    0,    0,
    0,    0,    0,  324,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  332,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  333,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  334,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  335,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  336,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  337,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  338,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  339,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  340,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  341,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  342,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  343,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  344,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  345,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  346,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  347,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  348,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  349,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  351,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  353,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  354,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  355,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  356,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  357,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  358,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  359,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  360,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  361,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  362,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  363,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  364,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  365,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  366,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  367,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  368,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  369,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  370,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  371,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  372,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  373,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  374,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  375,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  396,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  397,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  398,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  402,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,  403,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  404,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  405,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,    0,  202,  199,  406,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  407,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  408,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  409,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  410,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  424,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  425,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  426,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  427,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,  428,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,    0,    0,    0,    0,  198,    0,
  201,    0,  204,  194,    0,    0,  429,  202,  199,    0,
  200,    0,  203,    0,    0,    0,    0,    0,    0,  193,
    0,    0,    0,    0,  205,  195,  196,  197,  192,    0,
    0,    0,    0,  198,    0,  201,    0,  204,  194,    0,
    0,    0,  202,  199,    0,  200,    0,  203,    0,    0,
    0,    0,    0,    0,  193,    0,    0,    0,    0,  205,
  195,  196,  197,  192,  198,    0,  201,    0,  204,  194,
    0,    0,    0,  202,  199,    0,  200,    0,  203,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,  193,
    0,  195,  196,  197,  205,    0,    0,    0,    0,  198,
    0,  201,    0,  204,  194,    0,    0,    0,  202,  199,
    0,  200,    0,  203,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,  193,  205,  195,  196,  197,  198,
    0,  201,    0,  204,    0,    0,    0,    0,  202,  199,
    0,  200,    0,  203,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,  193,  195,  196,  197,    0,
  205,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,  143,  144,  145,  146,  147,  148,
  149,  150,  151,  152,  153,  154,  155,  156,  157,  158,
  205,  159,  160,  161,  162,  163,  164,  165,  166,  167,
  168,  169,  170,  171,  172,  173,  174,  175,  176,  177,
  178,  179,  180,  181,  182,  183,  184,  185,  186,  187,
  188,  189,    1,    0,    0,    0,    0,    0,    0,    0,
    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,
   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
   22,
};
short yycheck[] = {                                       3,
    4,    5,    6,    7,    8,    9,   10,   11,   12,   36,
   14,   15,   16,   17,   18,   19,   20,    4,    5,   69,
   70,   71,    9,   73,   33,   36,  258,   14,   15,   16,
   36,   18,   19,   37,   16,   33,   40,   41,   36,   43,
   36,   58,   40,   33,   36,   43,   36,   45,  263,   37,
   40,    0,   56,   43,   42,   45,   43,  334,  335,   47,
   43,    0,   45,   61,   68,  115,   64,   49,   50,   51,
   52,   61,   33,  263,   64,   36,  258,   58,   35,   40,
   37,  263,   43,   61,   45,   42,   43,   61,   45,   61,
   47,   61,   41,  258,   43,   44,   45,  258,  263,   58,
   82,   41,   41,   64,   44,   44,   94,   41,   41,  263,
   44,   44,   61,   58,  346,  347,  348,  126,   41,   58,
  258,   44,   36,  109,   63,  111,  112,  113,  126,   43,
  116,   45,   41,  258,  263,   44,  126,   94,   41,   61,
   61,   44,  192,  193,  194,  195,  196,  197,  258,  199,
  200,  201,  202,  203,  204,  205,  258,  258,  258,   40,
   40,   40,   40,   40,   40,  126,  216,  217,  218,  219,
  220,  221,  222,  223,  224,  225,  226,  227,  228,  229,
  230,  231,  232,  233,  234,  235,  236,  237,  238,  239,
  240,  241,  242,  243,  244,  245,  246,  247,  248,  249,
  250,  251,  252,  253,  254,  255,  256,  257,  212,  213,
  214,  215,  262,   36,   40,  265,   40,  267,   40,   40,
   43,   40,   45,   40,   40,  212,  213,  214,  215,   40,
  234,  235,   40,  260,  261,   40,  263,   40,   40,   40,
   40,  258,   40,   40,   40,   40,   33,  234,  235,   36,
  261,  257,  263,   40,   40,  261,   43,  263,   45,  257,
  258,  259,  258,  261,   12,  263,  258,  257,  258,  259,
   40,  261,   40,  263,  324,  258,  259,   64,   40,   40,
   40,   40,   40,   40,   40,  335,   40,  285,   40,   37,
   40,  341,   40,   41,  344,  285,  257,  258,  259,  260,
  261,   40,  263,   40,  302,  355,  356,  357,   56,  258,
  259,   40,  302,   40,   40,  365,  366,   40,  368,  369,
  370,  371,   40,   40,  285,  334,  335,  336,  337,  338,
  339,  340,  341,  342,  343,  344,  345,   40,    0,  126,
   61,  302,   41,  257,  258,  259,  260,  261,   94,  263,
  400,   41,  402,  403,  404,   41,  406,    0,   41,   41,
   41,   41,  412,   41,  414,    0,    0,    0,  372,  373,
  374,  375,  334,  335,    0,    0,    0,    0,  340,  341,
  342,  343,  344,    0,    0,  372,  373,  374,  375,    0,
   33,    0,   35,    0,   37,   38,    0,    0,   41,   42,
   43,   44,   45,    0,   47,   38,    0,   41,   41,  353,
   44,   44,   -1,   -1,   -1,   58,   -1,   60,   61,   62,
   63,   -1,   -1,   -1,   58,   58,   -1,   -1,   -1,   63,
   63,   -1,   -1,   -1,   -1,  258,  259,  260,  261,   33,
  263,   35,    0,   37,   38,   -1,   -1,   41,   42,   43,
   44,   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   58,   -1,   60,   61,   62,   63,
  257,  258,  259,    0,  261,   33,  263,   35,   -1,   37,
   38,  124,   -1,   41,   42,   43,   44,   45,   -1,   47,
  124,  124,   -1,   -1,   -1,   -1,   -1,   -1,  285,   -1,
   58,   -1,   60,   61,   62,   63,   33,    0,   35,    7,
    8,   38,   10,   11,   41,  302,   43,   44,   45,   17,
   -1,   -1,   20,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  124,   58,   -1,   60,   61,   62,   63,   -1,    0,   -1,
   33,   -1,   35,   -1,   -1,   38,    0,    0,   41,   -1,
   43,   44,   45,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   58,  124,   60,   61,   62,
   63,   33,   -1,   35,    0,    0,   38,   -1,   -1,   41,
   -1,   43,   44,   45,   38,   38,    0,   41,   41,   -1,
   44,   44,   -1,   -1,   -1,   -1,   58,  124,   60,   61,
   62,   63,    0,   -1,   58,   58,   -1,   -1,   -1,   63,
   63,   -1,   38,   38,   -1,   41,   41,   -1,   44,   44,
   -1,   -1,   -1,   -1,   38,   -1,   -1,   41,   -1,   -1,
   44,  124,   58,   58,   -1,   -1,   -1,   63,   63,   -1,
   38,   -1,   -1,   41,   58,   -1,   44,   -1,   -1,   63,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   58,   -1,  124,   -1,   33,   63,   35,   -1,   37,   38,
  124,  124,   41,   42,   43,   44,   45,   -1,   47,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   60,   61,   62,   63,   -1,   -1,   -1,  124,  124,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
  124,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   94,  124,   -1,   -1,   -1,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,  124,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   58,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   44,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,   44,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   41,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   -1,   -1,   -1,   -1,   33,   -1,
   35,   -1,   37,   38,   -1,   -1,   41,   42,   43,   -1,
   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   -1,   -1,   -1,   94,   60,   61,   62,   63,   -1,
   -1,   -1,   -1,   33,   -1,   35,   -1,   37,   38,   -1,
   -1,   -1,   42,   43,   -1,   45,   -1,   47,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,   -1,   94,
   60,   61,   62,   63,   33,   -1,   35,   -1,   37,   38,
   -1,   -1,   -1,   42,   43,   -1,   45,   -1,   47,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  124,
   -1,   60,   61,   62,   94,   -1,   -1,   -1,   -1,   33,
   -1,   35,   -1,   37,   38,   -1,   -1,   -1,   42,   43,
   -1,   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,  124,   94,   60,   61,   62,   33,
   -1,   35,   -1,   37,   -1,   -1,   -1,   -1,   42,   43,
   -1,   45,   -1,   47,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,  124,   60,   61,   62,   -1,
   94,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,  286,  287,  288,  289,  290,  291,
  292,  293,  294,  295,  296,  297,  298,  299,  300,  301,
   94,  303,  304,  305,  306,  307,  308,  309,  310,  311,
  312,  313,  314,  315,  316,  317,  318,  319,  320,  321,
  322,  323,  324,  325,  326,  327,  328,  329,  330,  331,
  332,  333,  256,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  264,  265,  266,  267,  268,  269,  270,  271,  272,  273,
  274,  275,  276,  277,  278,  279,  280,  281,  282,  283,
  284,
};
#define YYFINAL 23
#ifndef YYDEBUG
#define YYDEBUG 0
#endif
#define YYMAXTOKEN 348
#if YYDEBUG
char *yyname[] = {
"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
"'!'",0,"'#'","'$'","'%'","'&'",0,"'('","')'","'*'","'+'","','","'-'",0,"'/'",0,
0,0,0,0,0,0,0,0,0,"':'",0,"'<'","'='","'>'","'?'","'@'",0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,"'|'",0,"'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"STRING","NUMBER","FNUMBER",
"RANGE","VAR","WORD","COL","S_FORMAT","S_LABEL","S_LEFTSTRING","S_RIGHTSTRING",
"S_GET","S_PUT","S_MERGE","S_LET","S_WRITE","S_TBL","S_COPY","S_SHOW","S_ERASE",
"S_FILL","S_GOTO","S_DEFINE","S_UNDEFINE","S_VALUE","S_MDIR","S_HIDE","S_SET",
"K_FIXED","K_SUM","K_PROD","K_AVG","K_STDDEV","K_ACOS","K_ASIN","K_ATAN",
"K_ATAN2","K_CEIL","K_COS","K_EXP","K_FABS","K_FLOOR","K_HYPOT","K_LN","K_LOG",
"K_PI","K_POW","K_SIN","K_SQRT","K_TAN","K_DTR","K_RTD","K_MAX","K_MIN","K_RND",
"K_PV","K_FV","K_PMT","K_HOUR","K_MINUTE","K_SECOND","K_MONTH","K_DAY","K_YEAR",
"K_NOW","K_DATE","K_FMT","K_SUBSTR","K_STON","K_EQS","K_EXT","K_NVAL","K_SVAL",
"K_LOOKUP","K_STLOOKUP","K_INDEX","K_STINDEX","K_AUTO","K_AUTOCALC","K_BYROWS",
"K_BYCOLS","K_BYGRAPH","K_ITERATIONS","K_NUMERIC","K_PRESCALE","K_EXTFUN",
"K_CELLCUR","K_TOPROW","K_TBLSTYLE","K_TBL","K_LATEX","K_TEX",
};
char *yyrule[] = {
"$accept : command",
"command : S_LET var_or_range '=' e",
"command : S_LABEL var_or_range '=' e",
"command : S_LEFTSTRING var_or_range '=' e",
"command : S_RIGHTSTRING var_or_range '=' e",
"command : S_FORMAT COL ':' COL NUMBER NUMBER",
"command : S_FORMAT COL NUMBER NUMBER",
"command : S_GET strarg",
"command : S_MERGE strarg",
"command : S_MDIR strarg",
"command : S_PUT strarg range",
"command : S_PUT strarg",
"command : S_WRITE strarg range",
"command : S_WRITE strarg",
"command : S_TBL strarg range",
"command : S_TBL strarg",
"command : S_SHOW COL ':' COL",
"command : S_SHOW NUMBER ':' NUMBER",
"command : S_HIDE COL",
"command : S_HIDE NUMBER",
"command : S_COPY range var_or_range",
"command : S_ERASE",
"command : S_ERASE var_or_range",
"command : S_VALUE",
"command : S_VALUE var_or_range",
"command : S_FILL num num",
"command : S_FILL var_or_range num num",
"command : S_GOTO var_or_range",
"command : S_GOTO num",
"command : S_GOTO STRING",
"command : S_GOTO",
"command : S_DEFINE strarg",
"command : S_DEFINE strarg range",
"command : S_DEFINE strarg var",
"command : S_UNDEFINE var_or_range",
"command : S_SET setlist",
"command :",
"command : error",
"term : var",
"term : K_FIXED term",
"term : '@' K_SUM '(' var_or_range ')'",
"term : '@' K_PROD '(' var_or_range ')'",
"term : '@' K_AVG '(' var_or_range ')'",
"term : '@' K_STDDEV '(' var_or_range ')'",
"term : '@' K_MAX '(' var_or_range ')'",
"term : '@' K_MAX '(' e ',' expr_list ')'",
"term : '@' K_MIN '(' var_or_range ')'",
"term : '@' K_MIN '(' e ',' expr_list ')'",
"term : '@' K_ACOS '(' e ')'",
"term : '@' K_ASIN '(' e ')'",
"term : '@' K_ATAN '(' e ')'",
"term : '@' K_ATAN2 '(' e ',' e ')'",
"term : '@' K_CEIL '(' e ')'",
"term : '@' K_COS '(' e ')'",
"term : '@' K_EXP '(' e ')'",
"term : '@' K_FABS '(' e ')'",
"term : '@' K_FLOOR '(' e ')'",
"term : '@' K_HYPOT '(' e ',' e ')'",
"term : '@' K_LN '(' e ')'",
"term : '@' K_LOG '(' e ')'",
"term : '@' K_POW '(' e ',' e ')'",
"term : '@' K_SIN '(' e ')'",
"term : '@' K_SQRT '(' e ')'",
"term : '@' K_TAN '(' e ')'",
"term : '@' K_DTR '(' e ')'",
"term : '@' K_RTD '(' e ')'",
"term : '@' K_RND '(' e ')'",
"term : '@' K_PV '(' e ',' e ',' e ')'",
"term : '@' K_FV '(' e ',' e ',' e ')'",
"term : '@' K_PMT '(' e ',' e ',' e ')'",
"term : '@' K_HOUR '(' e ')'",
"term : '@' K_MINUTE '(' e ')'",
"term : '@' K_SECOND '(' e ')'",
"term : '@' K_MONTH '(' e ')'",
"term : '@' K_DAY '(' e ')'",
"term : '@' K_YEAR '(' e ')'",
"term : '@' K_NOW",
"term : '@' K_STON '(' e ')'",
"term : '@' K_EQS '(' e ',' e ')'",
"term : '@' K_DATE '(' e ')'",
"term : '@' K_FMT '(' e ',' e ')'",
"term : '@' K_INDEX '(' e ',' var_or_range ')'",
"term : '@' K_LOOKUP '(' e ',' var_or_range ')'",
"term : '@' K_LOOKUP '(' e ',' var_or_range ',' e ')'",
"term : '@' K_STLOOKUP '(' e ',' var_or_range ')'",
"term : '@' K_STLOOKUP '(' e ',' var_or_range ',' e ')'",
"term : '@' K_STINDEX '(' e ',' var_or_range ')'",
"term : '@' K_EXT '(' e ',' e ')'",
"term : '@' K_NVAL '(' e ',' e ')'",
"term : '@' K_SVAL '(' e ',' e ')'",
"term : '@' K_SUBSTR '(' e ',' e ',' e ')'",
"term : '(' e ')'",
"term : '+' term",
"term : '-' term",
"term : NUMBER",
"term : FNUMBER",
"term : K_PI",
"term : STRING",
"term : '~' term",
"term : '!' term",
"e : e '+' e",
"e : e '-' e",
"e : e '*' e",
"e : e '/' e",
"e : e '%' e",
"e : e '^' e",
"e : term",
"e : e '?' e ':' e",
"e : e '<' e",
"e : e '=' e",
"e : e '>' e",
"e : e '&' e",
"e : e '|' e",
"e : e '<' '=' e",
"e : e '!' '=' e",
"e : e '>' '=' e",
"e : e '#' e",
"expr_list : e",
"expr_list : expr_list ',' e",
"range : var ':' var",
"range : RANGE",
"var : COL NUMBER",
"var : '$' COL NUMBER",
"var : COL '$' NUMBER",
"var : '$' COL '$' NUMBER",
"var : VAR",
"var_or_range : range",
"var_or_range : var",
"num : NUMBER",
"num : FNUMBER",
"num : '-' num",
"num : '+' num",
"strarg : STRING",
"strarg : var",
"setlist :",
"setlist : setlist setitem",
"setitem : K_AUTO",
"setitem : K_AUTOCALC",
"setitem : '~' K_AUTO",
"setitem : '~' K_AUTOCALC",
"setitem : '!' K_AUTO",
"setitem : '!' K_AUTOCALC",
"setitem : K_BYCOLS",
"setitem : K_BYROWS",
"setitem : K_BYGRAPH",
"setitem : K_NUMERIC",
"setitem : '!' K_NUMERIC",
"setitem : K_PRESCALE",
"setitem : '!' K_PRESCALE",
"setitem : K_EXTFUN",
"setitem : '!' K_EXTFUN",
"setitem : K_CELLCUR",
"setitem : '!' K_CELLCUR",
"setitem : K_TOPROW",
"setitem : '!' K_TOPROW",
"setitem : K_ITERATIONS '=' NUMBER",
"setitem : K_TBLSTYLE '=' NUMBER",
"setitem : K_TBLSTYLE '=' K_TBL",
"setitem : K_TBLSTYLE '=' K_LATEX",
"setitem : K_TBLSTYLE '=' K_TEX",
};
#endif
#ifdef YYSTACKSIZE
#undef YYMAXDEPTH
#define YYMAXDEPTH YYSTACKSIZE
#else
#ifdef YYMAXDEPTH
#define YYSTACKSIZE YYMAXDEPTH
#else
#define YYSTACKSIZE 500
#define YYMAXDEPTH 500
#endif
#endif
int yydebug;
int yynerrs;
int yyerrflag;
int yychar;
short *yyssp;
YYSTYPE *yyvsp;
YYSTYPE yyval;
YYSTYPE yylval;
short yyss[YYSTACKSIZE];
YYSTYPE yyvs[YYSTACKSIZE];
#define yystacksize YYSTACKSIZE
#define YYABORT goto yyabort
#define YYREJECT goto yyabort
#define YYACCEPT goto yyaccept
#define YYERROR goto yyerrlab
int
yyparse()
{
    register int yym, yyn, yystate;
#if YYDEBUG
    register char *yys;
    extern char *getenv();

    if (yys = getenv("YYDEBUG"))
    {
        yyn = *yys;
        if (yyn >= '0' && yyn <= '9')
            yydebug = yyn - '0';
    }
#endif

    yynerrs = 0;
    yyerrflag = 0;
    yychar = (-1);

    yyssp = yyss;
    yyvsp = yyvs;
    *yyssp = yystate = 0;

yyloop:
    if (yyn = yydefred[yystate]) goto yyreduce;
    if (yychar < 0)
    {
        if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
        if (yydebug)
        {
            yys = 0;
            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
            if (!yys) yys = "illegal-symbol";
            printf("%sdebug: state %d, reading %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
    }
    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: state %d, shifting to state %d\n",
                    YYPREFIX, yystate, yytable[yyn]);
#endif
        if (yyssp >= yyss + yystacksize - 1)
        {
            goto yyoverflow;
        }
        *++yyssp = yystate = yytable[yyn];
        *++yyvsp = yylval;
        yychar = (-1);
        if (yyerrflag > 0)  --yyerrflag;
        goto yyloop;
    }
    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
        yyn = yytable[yyn];
        goto yyreduce;
    }
    if (yyerrflag) goto yyinrecovery;
#ifdef lint
    goto yynewerror;
#endif
yynewerror:
    yyerror("syntax error");
#ifdef lint
    goto yyerrlab;
#endif
yyerrlab:
    ++yynerrs;
yyinrecovery:
    if (yyerrflag < 3)
    {
        yyerrflag = 3;
        for (;;)
        {
            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: state %d, error recovery shifting\
 to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
#endif
                if (yyssp >= yyss + yystacksize - 1)
                {
                    goto yyoverflow;
                }
                *++yyssp = yystate = yytable[yyn];
                *++yyvsp = yylval;
                goto yyloop;
            }
            else
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: error recovery discarding state %d\n",
                            YYPREFIX, *yyssp);
#endif
                if (yyssp <= yyss) goto yyabort;
                --yyssp;
                --yyvsp;
            }
        }
    }
    else
    {
        if (yychar == 0) goto yyabort;
#if YYDEBUG
        if (yydebug)
        {
            yys = 0;
            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
            if (!yys) yys = "illegal-symbol";
            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
        yychar = (-1);
        goto yyloop;
    }
yyreduce:
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
                YYPREFIX, yystate, yyn, yyrule[yyn]);
#endif
    yym = yylen[yyn];
    yyval = yyvsp[1-yym];
    switch (yyn)
    {
case 1:
#line 150 "gram.y"
{ let(yyvsp[-2].rval.left.vp, yyvsp[0].enode); }
break;
case 2:
#line 152 "gram.y"
{ slet(yyvsp[-2].rval.left.vp, yyvsp[0].enode, 0); }
break;
case 3:
#line 154 "gram.y"
{ slet(yyvsp[-2].rval.left.vp, yyvsp[0].enode, -1); }
break;
case 4:
#line 156 "gram.y"
{ slet(yyvsp[-2].rval.left.vp, yyvsp[0].enode, 1); }
break;
case 5:
#line 158 "gram.y"
{ doformat(yyvsp[-4].ival,yyvsp[-2].ival,yyvsp[-1].ival,yyvsp[0].ival); }
break;
case 6:
#line 160 "gram.y"
{ doformat(yyvsp[-2].ival,yyvsp[-2].ival,yyvsp[-1].ival,yyvsp[0].ival); }
break;
case 7:
#line 161 "gram.y"
{  /* This tmp hack is because readfile
				    * recurses back through yyparse. */
				  char *tmp;
				  tmp = yyvsp[0].sval;
				  readfile (tmp, 1);
				  xfree(tmp);
				}
break;
case 8:
#line 168 "gram.y"
{
				  char *tmp;
				  tmp = yyvsp[0].sval;
				  readfile (tmp, 0);
				  xfree(tmp);
				}
break;
case 9:
#line 175 "gram.y"
{ if (mdir) xfree(mdir); mdir = yyvsp[0].sval; }
break;
case 10:
#line 177 "gram.y"
{ (void) writefile(yyvsp[-1].sval, (yyvsp[0].rval.left.vp)->row, 
			 	(yyvsp[0].rval.left.vp)->col, (yyvsp[0].rval.right.vp)->row,
			 	(yyvsp[0].rval.right.vp)->col);
			 	xfree(yyvsp[-1].sval); }
break;
case 11:
#line 182 "gram.y"
{ (void) writefile (yyvsp[0].sval, 0, 0, maxrow, maxcol);
			 	xfree(yyvsp[0].sval); }
break;
case 12:
#line 184 "gram.y"
{ (void) printfile(yyvsp[-1].sval, (yyvsp[0].rval.left.vp)->row, 
			 (yyvsp[0].rval.left.vp)->col, (yyvsp[0].rval.right.vp)->row,
			 (yyvsp[0].rval.right.vp)->col);
			 xfree(yyvsp[-1].sval); }
break;
case 13:
#line 188 "gram.y"
{ (void) printfile (yyvsp[0].sval, 0, 0, maxrow, maxcol);
			 xfree(yyvsp[0].sval); }
break;
case 14:
#line 190 "gram.y"
{ (void) tblprintfile(yyvsp[-1].sval, (yyvsp[0].rval.left.vp)->row, 
			 (yyvsp[0].rval.left.vp)->col, (yyvsp[0].rval.right.vp)->row,
			 (yyvsp[0].rval.right.vp)->col);
			 xfree(yyvsp[-1].sval); }
break;
case 15:
#line 194 "gram.y"
{ (void)tblprintfile (yyvsp[0].sval, 0, 0, maxrow, maxcol);
			 xfree(yyvsp[0].sval); }
break;
case 16:
#line 197 "gram.y"
{ showcol( yyvsp[-2].ival, yyvsp[0].ival); }
break;
case 17:
#line 199 "gram.y"
{ showrow( yyvsp[-2].ival, yyvsp[0].ival); }
break;
case 18:
#line 201 "gram.y"
{ hide_col( yyvsp[0].ival ); }
break;
case 19:
#line 203 "gram.y"
{ hide_row( yyvsp[0].ival ); }
break;
case 20:
#line 205 "gram.y"
{ copy(yyvsp[-1].rval.left.vp,yyvsp[-1].rval.right.vp,
					yyvsp[0].rval.left.vp,yyvsp[0].rval.right.vp); }
break;
case 21:
#line 208 "gram.y"
{ eraser(lookat(showsr, showsc),
				        lookat(currow, curcol)); }
break;
case 22:
#line 211 "gram.y"
{ eraser(yyvsp[0].rval.left.vp, yyvsp[0].rval.right.vp); }
break;
case 23:
#line 212 "gram.y"
{ valueize_area(showsr, showsc, currow, curcol);
				 modflg++; }
break;
case 24:
#line 214 "gram.y"
{ valueize_area((yyvsp[0].rval.left.vp)->row,
				(yyvsp[0].rval.left.vp)->col,
				(yyvsp[0].rval.right.vp)->row,
				(yyvsp[0].rval.right.vp)->col); modflg++; }
break;
case 25:
#line 218 "gram.y"
{ fill(lookat(showsr, showsc),
				      lookat(currow, curcol), yyvsp[-1].fval, yyvsp[0].fval); }
break;
case 26:
#line 221 "gram.y"
{ fill(yyvsp[-2].rval.left.vp, yyvsp[-2].rval.right.vp, yyvsp[-1].fval, yyvsp[0].fval); }
break;
case 27:
#line 222 "gram.y"
{moveto(yyvsp[0].rval.left.vp->row, yyvsp[0].rval.left.vp->col);}
break;
case 28:
#line 223 "gram.y"
{num_search(yyvsp[0].fval);}
break;
case 29:
#line 224 "gram.y"
{str_search(yyvsp[0].sval);}
break;
case 30:
#line 225 "gram.y"
{go_last();}
break;
case 31:
#line 226 "gram.y"
{ struct ent_ptr arg1, arg2;
					arg1.vp = lookat(showsr, showsc);
					arg1.vf = 0;
					arg2.vp = lookat(currow, curcol);
					arg2.vf = 0;
					add_range(yyvsp[0].sval, arg1, arg2, 1); }
break;
case 32:
#line 233 "gram.y"
{ add_range(yyvsp[-1].sval, yyvsp[0].rval.left, yyvsp[0].rval.right, 1); }
break;
case 33:
#line 234 "gram.y"
{ add_range(yyvsp[-1].sval, yyvsp[0].ent, yyvsp[0].ent, 0); }
break;
case 34:
#line 235 "gram.y"
{ del_range(yyvsp[0].rval.left.vp, yyvsp[0].rval.right.vp); }
break;
case 38:
#line 240 "gram.y"
{ yyval.enode = new_var('v', yyvsp[0].ent); }
break;
case 39:
#line 241 "gram.y"
{ yyval.enode = new ('f', ENULL, yyvsp[0].enode); }
break;
case 40:
#line 243 "gram.y"
{ yyval.enode = new_range(REDUCE | '+', yyvsp[-1].rval); }
break;
case 41:
#line 245 "gram.y"
{ yyval.enode = new_range (REDUCE | '*', yyvsp[-1].rval); }
break;
case 42:
#line 247 "gram.y"
{ yyval.enode = new_range (REDUCE | 'a', yyvsp[-1].rval); }
break;
case 43:
#line 249 "gram.y"
{ yyval.enode = new_range (REDUCE | 's', yyvsp[-1].rval); }
break;
case 44:
#line 251 "gram.y"
{ yyval.enode = new_range (REDUCE | MAX, yyvsp[-1].rval); }
break;
case 45:
#line 253 "gram.y"
{ yyval.enode = new(LMAX, yyvsp[-1].enode, yyvsp[-3].enode); }
break;
case 46:
#line 255 "gram.y"
{ yyval.enode = new_range (REDUCE | MIN, yyvsp[-1].rval); }
break;
case 47:
#line 257 "gram.y"
{ yyval.enode = new(LMIN, yyvsp[-1].enode, yyvsp[-3].enode); }
break;
case 48:
#line 259 "gram.y"
{ yyval.enode = new(ACOS, ENULL, yyvsp[-1].enode); }
break;
case 49:
#line 260 "gram.y"
{ yyval.enode = new(ASIN, ENULL, yyvsp[-1].enode); }
break;
case 50:
#line 261 "gram.y"
{ yyval.enode = new(ATAN, ENULL, yyvsp[-1].enode); }
break;
case 51:
#line 262 "gram.y"
{ yyval.enode = new(ATAN2, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 52:
#line 263 "gram.y"
{ yyval.enode = new(CEIL, ENULL, yyvsp[-1].enode); }
break;
case 53:
#line 264 "gram.y"
{ yyval.enode = new(COS, ENULL, yyvsp[-1].enode); }
break;
case 54:
#line 265 "gram.y"
{ yyval.enode = new(EXP, ENULL, yyvsp[-1].enode); }
break;
case 55:
#line 266 "gram.y"
{ yyval.enode = new(FABS, ENULL, yyvsp[-1].enode); }
break;
case 56:
#line 267 "gram.y"
{ yyval.enode = new(FLOOR, ENULL, yyvsp[-1].enode); }
break;
case 57:
#line 268 "gram.y"
{ yyval.enode = new(HYPOT, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 58:
#line 269 "gram.y"
{ yyval.enode = new(LOG, ENULL, yyvsp[-1].enode); }
break;
case 59:
#line 270 "gram.y"
{ yyval.enode = new(LOG10, ENULL, yyvsp[-1].enode); }
break;
case 60:
#line 271 "gram.y"
{ yyval.enode = new(POW, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 61:
#line 272 "gram.y"
{ yyval.enode = new(SIN, ENULL, yyvsp[-1].enode); }
break;
case 62:
#line 273 "gram.y"
{ yyval.enode = new(SQRT, ENULL, yyvsp[-1].enode); }
break;
case 63:
#line 274 "gram.y"
{ yyval.enode = new(TAN, ENULL, yyvsp[-1].enode); }
break;
case 64:
#line 275 "gram.y"
{ yyval.enode = new(DTR, ENULL, yyvsp[-1].enode); }
break;
case 65:
#line 276 "gram.y"
{ yyval.enode = new(RTD, ENULL, yyvsp[-1].enode); }
break;
case 66:
#line 277 "gram.y"
{ yyval.enode = new(RND, ENULL, yyvsp[-1].enode); }
break;
case 67:
#line 279 "gram.y"
{ yyval.enode = new(PV,  yyvsp[-5].enode,new(':',yyvsp[-3].enode,yyvsp[-1].enode)); }
break;
case 68:
#line 280 "gram.y"
{ yyval.enode = new(FV,  yyvsp[-5].enode,new(':',yyvsp[-3].enode,yyvsp[-1].enode)); }
break;
case 69:
#line 281 "gram.y"
{ yyval.enode = new(PMT, yyvsp[-5].enode,new(':',yyvsp[-3].enode,yyvsp[-1].enode)); }
break;
case 70:
#line 283 "gram.y"
{ yyval.enode = new(HOUR,ENULL, yyvsp[-1].enode); }
break;
case 71:
#line 284 "gram.y"
{ yyval.enode = new(MINUTE,ENULL, yyvsp[-1].enode); }
break;
case 72:
#line 285 "gram.y"
{ yyval.enode = new(SECOND,ENULL, yyvsp[-1].enode); }
break;
case 73:
#line 286 "gram.y"
{ yyval.enode = new(MONTH,ENULL,yyvsp[-1].enode); }
break;
case 74:
#line 287 "gram.y"
{ yyval.enode = new(DAY, ENULL, yyvsp[-1].enode); }
break;
case 75:
#line 288 "gram.y"
{ yyval.enode = new(YEAR, ENULL, yyvsp[-1].enode); }
break;
case 76:
#line 289 "gram.y"
{ yyval.enode = new(NOW, ENULL, ENULL);}
break;
case 77:
#line 290 "gram.y"
{ yyval.enode = new(STON, ENULL, yyvsp[-1].enode); }
break;
case 78:
#line 291 "gram.y"
{ yyval.enode = new (EQS, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 79:
#line 292 "gram.y"
{ yyval.enode = new(DATE, ENULL, yyvsp[-1].enode); }
break;
case 80:
#line 293 "gram.y"
{ yyval.enode = new(FMT, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 81:
#line 295 "gram.y"
{ yyval.enode = new(INDEX, yyvsp[-3].enode, new_range(REDUCE | INDEX, yyvsp[-1].rval)); }
break;
case 82:
#line 297 "gram.y"
{ yyval.enode = new(LOOKUP, yyvsp[-3].enode,
			    new(ELIST, new_range(REDUCE | LOOKUP, yyvsp[-1].rval),
				new_const('k', (double) 1.0))); }
break;
case 83:
#line 301 "gram.y"
{ yyval.enode = new(LOOKUP, yyvsp[-5].enode,
			    new(ELIST, new_range(REDUCE | LOOKUP, yyvsp[-3].rval), yyvsp[-1].enode)); }
break;
case 84:
#line 304 "gram.y"
{ yyval.enode = new(STLOOKUP, yyvsp[-3].enode,
			    new(ELIST, new_range(REDUCE | STLOOKUP, yyvsp[-1].rval),
				new_const('k', (double) 1.0))); }
break;
case 85:
#line 308 "gram.y"
{ yyval.enode = new(STLOOKUP, yyvsp[-5].enode,
			    new(ELIST, new_range(REDUCE | STLOOKUP, yyvsp[-3].rval), yyvsp[-1].enode)); }
break;
case 86:
#line 311 "gram.y"
{ yyval.enode = new(STINDEX, yyvsp[-3].enode, new_range(REDUCE | STINDEX, yyvsp[-1].rval)); }
break;
case 87:
#line 312 "gram.y"
{ yyval.enode = new(EXT, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 88:
#line 313 "gram.y"
{ yyval.enode = new(NVAL, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 89:
#line 314 "gram.y"
{ yyval.enode = new(SVAL, yyvsp[-3].enode, yyvsp[-1].enode); }
break;
case 90:
#line 316 "gram.y"
{ yyval.enode = new(SUBSTR, yyvsp[-5].enode, new(',', yyvsp[-3].enode, yyvsp[-1].enode)); }
break;
case 91:
#line 317 "gram.y"
{ yyval.enode = yyvsp[-1].enode; }
break;
case 92:
#line 318 "gram.y"
{ yyval.enode = yyvsp[0].enode; }
break;
case 93:
#line 319 "gram.y"
{ yyval.enode = new ('m', ENULL, yyvsp[0].enode); }
break;
case 94:
#line 320 "gram.y"
{ yyval.enode = new_const('k', (double) yyvsp[0].ival); }
break;
case 95:
#line 321 "gram.y"
{ yyval.enode = new_const('k', yyvsp[0].fval); }
break;
case 96:
#line 322 "gram.y"
{ yyval.enode = new_const('k', (double)3.14159265358979323846); }
break;
case 97:
#line 323 "gram.y"
{ yyval.enode = new_str(yyvsp[0].sval); }
break;
case 98:
#line 324 "gram.y"
{ yyval.enode = new ('~', ENULL, yyvsp[0].enode); }
break;
case 99:
#line 325 "gram.y"
{ yyval.enode = new ('~', ENULL, yyvsp[0].enode); }
break;
case 100:
#line 328 "gram.y"
{ yyval.enode = new ('+', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 101:
#line 329 "gram.y"
{ yyval.enode = new ('-', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 102:
#line 330 "gram.y"
{ yyval.enode = new ('*', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 103:
#line 331 "gram.y"
{ yyval.enode = new ('/', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 104:
#line 332 "gram.y"
{ yyval.enode = new ('%', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 105:
#line 333 "gram.y"
{ yyval.enode = new ('^', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 107:
#line 335 "gram.y"
{ yyval.enode = new ('?', yyvsp[-4].enode, new(':', yyvsp[-2].enode, yyvsp[0].enode)); }
break;
case 108:
#line 336 "gram.y"
{ yyval.enode = new ('<', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 109:
#line 337 "gram.y"
{ yyval.enode = new ('=', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 110:
#line 338 "gram.y"
{ yyval.enode = new ('>', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 111:
#line 339 "gram.y"
{ yyval.enode = new ('&', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 112:
#line 340 "gram.y"
{ yyval.enode = new ('|', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 113:
#line 341 "gram.y"
{ yyval.enode = new ('~', ENULL, new ('>', yyvsp[-3].enode, yyvsp[0].enode)); }
break;
case 114:
#line 342 "gram.y"
{ yyval.enode = new ('~', ENULL, new ('=', yyvsp[-3].enode, yyvsp[0].enode)); }
break;
case 115:
#line 343 "gram.y"
{ yyval.enode = new ('~', ENULL, new ('<', yyvsp[-3].enode, yyvsp[0].enode)); }
break;
case 116:
#line 344 "gram.y"
{ yyval.enode = new ('#', yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 117:
#line 347 "gram.y"
{ yyval.enode = new(ELIST, ENULL, yyvsp[0].enode); }
break;
case 118:
#line 348 "gram.y"
{ yyval.enode = new(ELIST, yyvsp[-2].enode, yyvsp[0].enode); }
break;
case 119:
#line 351 "gram.y"
{ yyval.rval.left = yyvsp[-2].ent; yyval.rval.right = yyvsp[0].ent; }
break;
case 120:
#line 352 "gram.y"
{ yyval.rval = yyvsp[0].rval; }
break;
case 121:
#line 355 "gram.y"
{ yyval.ent.vp = lookat(yyvsp[0].ival , yyvsp[-1].ival); yyval.ent.vf = 0;}
break;
case 122:
#line 356 "gram.y"
{ yyval.ent.vp = lookat(yyvsp[0].ival , yyvsp[-1].ival);
					yyval.ent.vf = FIX_COL;}
break;
case 123:
#line 358 "gram.y"
{ yyval.ent.vp = lookat(yyvsp[0].ival , yyvsp[-2].ival);
					yyval.ent.vf = FIX_ROW;}
break;
case 124:
#line 360 "gram.y"
{ yyval.ent.vp = lookat(yyvsp[0].ival , yyvsp[-2].ival);
					yyval.ent.vf = FIX_ROW | FIX_COL;}
break;
case 125:
#line 362 "gram.y"
{ yyval.ent = yyvsp[0].rval.left; }
break;
case 126:
#line 365 "gram.y"
{ yyval.rval = yyvsp[0].rval; }
break;
case 127:
#line 366 "gram.y"
{ yyval.rval.left = yyvsp[0].ent; yyval.rval.right = yyvsp[0].ent; }
break;
case 128:
#line 369 "gram.y"
{ yyval.fval = (double) yyvsp[0].ival; }
break;
case 129:
#line 370 "gram.y"
{ yyval.fval = yyvsp[0].fval; }
break;
case 130:
#line 371 "gram.y"
{ yyval.fval = -yyvsp[0].fval; }
break;
case 131:
#line 372 "gram.y"
{ yyval.fval = yyvsp[0].fval; }
break;
case 132:
#line 375 "gram.y"
{ yyval.sval = yyvsp[0].sval; }
break;
case 133:
#line 376 "gram.y"
{
				    char *s, *s1;
				    s1 = yyvsp[0].ent.vp->label;
				    if (!s1)
					s1 = "NULL_STRING";
				    s = xmalloc((unsigned)strlen(s1)+1);
				    (void) strcpy(s, s1);
				    yyval.sval = s;
				}
break;
case 136:
#line 391 "gram.y"
{ setauto(1); }
break;
case 137:
#line 392 "gram.y"
{ setauto(1); }
break;
case 138:
#line 393 "gram.y"
{ setauto(0); }
break;
case 139:
#line 394 "gram.y"
{ setauto(0); }
break;
case 140:
#line 395 "gram.y"
{ setauto(0); }
break;
case 141:
#line 396 "gram.y"
{ setauto(0); }
break;
case 142:
#line 397 "gram.y"
{ setorder(BYCOLS); }
break;
case 143:
#line 398 "gram.y"
{ setorder(BYROWS); }
break;
case 144:
#line 399 "gram.y"
{ setorder(BYGRAPH); }
break;
case 145:
#line 400 "gram.y"
{ numeric = 1; }
break;
case 146:
#line 401 "gram.y"
{ numeric = 0; }
break;
case 147:
#line 402 "gram.y"
{ prescale = 0.01; }
break;
case 148:
#line 403 "gram.y"
{ prescale = 1.0; }
break;
case 149:
#line 404 "gram.y"
{ extfunc = 1; }
break;
case 150:
#line 405 "gram.y"
{ extfunc = 0; }
break;
case 151:
#line 406 "gram.y"
{ showcell = 1; }
break;
case 152:
#line 407 "gram.y"
{ showcell = 0; }
break;
case 153:
#line 408 "gram.y"
{ showtop = 1; }
break;
case 154:
#line 409 "gram.y"
{ showtop = 0; }
break;
case 155:
#line 410 "gram.y"
{ setiterations(yyvsp[0].ival); }
break;
case 156:
#line 411 "gram.y"
{ tbl_style = yyvsp[0].ival; }
break;
case 157:
#line 412 "gram.y"
{ tbl_style = TBL; }
break;
case 158:
#line 413 "gram.y"
{ tbl_style = LATEX; }
break;
case 159:
#line 414 "gram.y"
{ tbl_style = TEX; }
break;
#line 1940 "y.tab.c"
    }
    yyssp -= yym;
    yystate = *yyssp;
    yyvsp -= yym;
    yym = yylhs[yyn];
    if (yystate == 0 && yym == 0)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: after reduction, shifting from state 0 to\
 state %d\n", YYPREFIX, YYFINAL);
#endif
        yystate = YYFINAL;
        *++yyssp = YYFINAL;
        *++yyvsp = yyval;
        if (yychar < 0)
        {
            if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
            if (yydebug)
            {
                yys = 0;
                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
                if (!yys) yys = "illegal-symbol";
                printf("%sdebug: state %d, reading %d (%s)\n",
                        YYPREFIX, YYFINAL, yychar, yys);
            }
#endif
        }
        if (yychar == 0) goto yyaccept;
        goto yyloop;
    }
    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
        yystate = yytable[yyn];
    else
        yystate = yydgoto[yym];
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: after reduction, shifting from state %d \
to state %d\n", YYPREFIX, *yyssp, yystate);
#endif
    if (yyssp >= yyss + yystacksize - 1)
    {
        goto yyoverflow;
    }
    *++yyssp = yystate;
    *++yyvsp = yyval;
    goto yyloop;
yyoverflow:
    yyerror("yacc stack overflow");
yyabort:
    return (1);
yyaccept:
    return (0);
}

Added help.c.













































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/*
 * Help functions for sc 
 * R. Bond, 1988
 * $Revision: 1.1 $
 */

#include <curses.h>
#include "sc.h"

char *intro[] = {
" ",
" Overview:",
" ",
" A:   This overview",
" B:   Options",
" C:   Cursor movement commands",
" D:   Cell entry and editing commands",
" E:   File commands",
" F:   Row and column commands",
" G:   Range commands",
" H:   Miscellaneous commands",
" I:   Variable names/Expressions",
" J:   Range functions",
" K:   Numeric functions",
" L:   String functions",
" M:   Financial functions",
" N:   Time and date functions",
" ",
" Q:   Return to main spreadsheet",
0
};

char *options[] = {
" ",
" B: Options",
" ",
"     ^To  Toggle options. Toggle one option selected by o:",
" ",
"          a    Recalculate automatically or on ``@'' commands.",
"          c    Current cell highlighting enable/disable.",  
"          e    External function execution enable/disable.",
"          n    If enabled, a digit starts a numeric value.",
"          t    Top line display enable/disable.",
"          x    Encrypt/decrypt database and listing files.",
"          $    Dollar prescale.  If enabled, all numeric constants.",
"               (not expressions) entered are multipled by 0.01.",
" ",
"     S    Set options.  Options include:",
" ",
"          byrows        Recalculate in row order. (default)",
"          bycols        Recalculate in column order.",
"          iterations=n  Set the number of iterations allowed. (10)",
"          tblstyle=xx   Set ``T'' output style to:",
"                        0 (none), tex, latex, or tbl.",
0
};

char *cursor[] = {
" ",
" C: Cell cursor movement (always OK):",
" ",
"     ^N ^P ^B ^F Down, up, back, forward",
"     ^Ed         Go to end of range.  Follow ^E by a direction indicator",
"                 such as ^P or j.",
"     Arrow keys (if the terminal and termcap support them.)",
" ",
" Cell cursor movement if no prompt active:",
"     j,k,l,h    Down, up, right, left",
"     SPACE      Forward",
"     ^H         Back",
"     TAB        Forward, otherwise starts/ends a range",
"     ^          Up to row 0 of the current column.",
"     #          Down to the last valid row of the current column.",
"     0          Back to column A.  Preface with ^U if numeric mode.",
"     $          Forward to the last valid column of the current row.",
"     b          Back then up to the previous valid cell.",
"     w          Forward then down to the next valid cell.",
"     g          Go to a cell.  Cell name, range name, quoted string,",
"                or a number specify which cell.",
0
};


char *cell[] = {
" ",
" D: Cell entry and editing commands:",
" ",
"     =    Enter a numeric constant or expression.",
"     <    Enter a left justified string or string expression.",
"     \",>  Enter a right justified string or string expression.",
"     e    Edit the current cell's numeric value.",
"     E    Edit the current cell's string part.",
"     x    Clear the current cell.",
"     c    Copy the last marked cell to the current cell.",
"     m    Mark a cell to be used as the source for ``c''",
"     +    Increment numeric part",
"     -    Decrement numeric part",
" ",
"     In numeric mode, a decimal digit, ``+'', ``-'', and ``.'' all start",
"     a new numeric constant or expression.",
0
};


char *file[] = {
" ",
" E: File commands:",
" ",
"     G    Get a new database from a file. ",
"     M    Merge a new file into the current database.",
"     P    Put the current database into a file.",
"     W    Write a listing of the current database into a file in",
"          a form that matches its appearance on the screen.",
"     T    Write a listing of the current database to a file, but",
"          put delimiters between each pair of fields.",
"          Optionally brackets output with control lines for ``tbl'',",
"          ``LaTeX'', or ``TeX''.",
" ",
"     If encryption mode is set, file I/O will be encrypted/decrypted.",
"     ``\"| program\"'' for a file name will pipe (unencrypted) output to",
"     a program for Put, Write and Table.  If a cell name is used",
"     as the file name, the cell's string part will be used as the",
"     file name.",
0
};


char *row[] = {
" ",
" F: Row and column commands:",
" ",
"     ir, ic      Insert a new, empty row (column)",
"     ar, ac      Append a new copy of the current row (column)",
"     dr, dc      Delete the current row (column)",
"     pr, pc, pm  Pull deleted cells back into the spreadsheet",
"                 Insert rows, columns or merge the cells.",
"     vr, vc      Remove expressions from the affected rows (columns),",
"                 leaving only the values.",
"     zr, zc      Hide (``zap'') the current row (column)",
"     sr, sc      Show hidden rows (columns)",
"     f           Set the output format to be used with the values of",
"                 each cell in this column.  Enter field width and",
"                 number of fractional digits.  A preceding count can be",
"                 used to change more than one column.",
" ",
"     Commands which move or copy cells also modify the row and column ",
"     references in the new cell expressions.  Use ``fixed'' or the",
"     ``$'' style cell reference to supress the change.",
0
};


char *range[] = {
" ",
" G: Range commands:",
" ",
"     /x   Clear a range. ",
"     /v   Remove the expressions from a range of cells, leaving ",
"          just the values.",
"     /c   Copy a source range to a destination range.",
"     /f   Fill a range with constant values starting with a given",
"          value and increasing by a given increment.",
"     /d   Assign a name to a cell or a range of cells.  Give the",
"          the name, surrounded by quotes, and either a cell name such",
"          as ``A10'' or a range such as ``a1:b20''.",
"     /s   Shows the currently defined range names.  Pipe output to",
"          sort, then to less.",
"     /u   Use this command to undefine a previously defined range",
"          name.",
" ",
"     Range operations affect a rectangular region on the screen",
"     defined by the upper left and lower right cells in the region.",
"     A range is specified by giving the cell names separated by ``:'',",
"     such as ``a20:k52''.  Another way to refer to a range is to use",
"     a name previously defined using ``/d''.",
0
};


char *misc[] = {
" ",
" H: Miscellaneous commands:",
" ",
"     Q q ^C   Exit from the program.",
"     ^G ESC   Abort entry of the current command.",
"     ?        Help",
"     !        Shell escape.  Enter a command to run.  ``!!'' repeats",
"              the last command.  Just ``!'' starts an interactive shell.",
"     ^L       Redraw the screen.",
"     ^R       Redraw the screen.  Highlight cells with values but no",
"              expressions.",
"     ^X       Redraw the screen.  Show formulas, not values.",
"     @        Recalculate the spreadsheet.",
"     ^V       Type, in the command line, the name of the current cell.",
"     ^W       Type, in the command line, the current cell's expression.",
"     ^A       Type, in the command line, the current cell's numeric value.",
"     TAB      When the character cursor is on the top line TAB can be used",
"              to start or stop the display of the default range.",
0
};

char *var[] = {
" ",
" I: Variable names:",
" ",
"     K20    Row and column can vary on copies.",
"     $K$20  Row and column stay fixed on copies.",
"     $K20   Row can vary; column stays fixed on copies.",
"     K$20   Row stays fixed; column can vary on copies.",
"     fixed  holds following expession fixed on copies.",
"     Cells and ranges can also be assigned a symbolic name via the",
"     range command ``/d''.",
" ",
" Expressions:",
"     -e      Negation                e<=e  Less than or equal",
"     e+e     Addition                e=e   Equal",
"     e-e     Subtraction             e!=e  Not Equal",
"     e*e     Multiplication          e>=e  Greater than or equal",
"     e/e     Division                e>e  Greater than",
"     e%e     Modulo                  e<e  Less than",
"     e^e     Exponentiation          e&e  Boolean operator AND.",
"     ~e      Boolean operator NOT    e|e     Boolean operator OR",
"     e?e1:e2 Conditional: If the e is non zero then then e1, otherwise e2.",
"     Terms may be constants, variable names, and parenthesized expressions.",
0
};

char *rangef[] = {
" ",
" J: Range functions:",
" ",
"     @sum(r)           Sum all valid cells in the range.",
"     @prod(r)          Multiply together all valid cells in the range.",
"     @avg(r)           Average all valid cells in range.",
"     @max(r)           Return the maximum value in the range.",
"     @min(r)           Return the minimum value in the range.",
"                       See also the numeric versions of max and min.",
"     @stddev(r)        Return the sample standard deviation of ",
"                       the cells in the range.",
"     @index(e,r)       Return the numeric value of the cell at index e",
"                       into range r.",
"     @stindex(e,r)     Return the string value of the cell at index e",
"                       into range r.",
"     @lookup(e,r)      Search through the range r for a value that",
"                       matches e.  The value returned is that from the",
"                       next row and the same column as the match, if",
"                       the range was a single row, or the value from",
"                       the next column and the same row as the match if",
"                       the range was a single column.",
0
};

char *numericf[] = {
" ",
" K: Numeric functions:",
" ",
"     @atan2(e1,e2)     Arc tangent of e1/e2.",
"     @ceil(e)          Smallest integer not less than e.",
"     @eqs(se1,se2)     1 if string expr se1 has the same value as se2.",
"     @exp(e)           Exponential function of e.",
"     @fabs(e)          Absolute value of e.",
"     @floor(e)         The largest integer not greater than e.",
"     @hypot(x,y)       Sqrt(x*x+y*y).",
"     @max(e1,e2,...)   The maximum of the values of the e's.",
"     @min(e1,e2,...)   The minimum of the values of the e's",
"     @nval(se,e)       The numeric value of a named cell.",
"     pi                A constant quite close to pi.",
"     @pow(e1,e2)       e1 raised to the power of e2.",
"     @rnd(e)           Round e to the nearest integer.",
"     @sqrt(e)          Square root of e.",
"     @ston(se)         Convert string expr se to a numeric",
"     @ln(e)   @log(e)           Natural/base 10 logarithm of e.",
"     @dtr(e)  @rtd(e)           Convert degrees to/from radians.",
"     @cos(e)  @sin(e)  @tan(e)  Trig functions of radian arguments.",
"     @asin(e) @acos(e) @atan(e) Inverse trig function.",
0
};

char *stringf[] = {
" ",
" L: String functions:",
" ",
"     #                 Concatenate strings.  For example, the",
"                       string expression ``A0 # \"zy dog\"'' yields",
"                       ``the lazy dog'' if A0 is ``the la''.",
"     @substr(se,e1,e2) Extract characters e1 through e2 from the",
"                       string expression se.  For example,",
"                       ``@substr(\"Nice jacket\" 4, 7)'' yields ",
"                       ``e jac''.",
"     @fmt(se,e)        Convert a number to a string using sprintf(3).",
"                       For example,  ``@fmt(\"*%6.3f*\",10.5)'' yields",
"                       ``*10.500*''.  Use formats are e, E, f, g, and G.", 
"     @sval(se,e)       Return the string value of a cell selected by name.",
"     @ext(se,e)        Call an external function (program or",
"                       script).  Convert e to a string and append it",
"                       to the command line as an argument.  @ext yields",
"                       a string: the first line printed to standard",
"                       output by the command.",
"     String expressions are made up of constant strings (characters",
"     surrounded by quotes), variables, and string functions.",
0
};


char *finf[] = {
" ",
" M: Financial functions:",
" ",
"     @pmt(e1,e2,e3)    @pmt(60000,.01,360) computes the monthly",
"                       payments for a $60000 mortgage at 12%",
"                       annual interest (.01 per month) for 30",
"                       years (360 months).",
" ",
"     @fv(e1,e2,e3)     @fv(100,.005,36) computes the future value",
"                       for of 36 monthly payments of $100 at 6%",
"                       interest (.005 per month).  It answers the",
"                       question:  ``How much will I have in 2",
"                       years if I deposit $100 per month in a",
"                       savings account paying 6% interest com-",
"                       pounded monthly?''",
" ",
"     @pv(e1,e2,e3)     @pv(1000,.015,36) computes the present",
"                       value of an a ordinary annuity of 36",
"                       monthly payments of $1000 at 18% annual",
"                       interest.  It answers the question: ``How",
"                       much can I borrow at 18% for 30 years if I",
"                       pay $1000 per month?''",
0
};


char *timef[] = {
" ",
" N: Time and date functions:",
" ",
"     @now              Return the current time encoded as the",
"                       number of seconds since December 31, 1969,",
"                       midnight, GMT.",
" ",
"     All of the following take an argument expressed in seconds:",
" ",
"     @date(e)          Convert the time in seconds to a date",
"                       string 24 characters long in the following",
"                       form: ``Sun Sep 16 01:03:52 1973''.  Note",
"                       that you can extract pieces of this fixed format",
"                       string with @substr.",
"     @year(e)          Return the year.  Valid years begin with 1970.",
"     @month(e)         Return the month: 1 (Jan) to 12 (Dec).",
"     @day(e)           Return the day of the month: 1 to 31.",
"     @hour(e)          Return the number of hours since midnight: 0 to 23.",
"     @minute(e)        Return the number of minutes since the",
"                       last full hour: 0 to 59.",
"     @second(e)        Return the number of seconds since the",
"                       last full minute: 0 to 59.",
0
};

help()
{
    int option;
    char **ns = intro;

    while((option = pscreen(ns)) != 'q' && option != 'Q') {
    	switch (option) {
	case 'a': case 'A': ns = intro; break;
	case 'b': case 'B': ns = options; break;
	case 'c': case 'C': ns = cursor; break;
	case 'd': case 'D': ns = cell; break;
	case 'e': case 'E': ns = file; break;
	case 'f': case 'F': ns = row; break;
	case 'g': case 'G': ns = range; break;
	case 'h': case 'H': ns = misc; break;
	case 'i': case 'I': ns = var; break;
	case 'j': case 'J': ns = rangef; break;
	case 'k': case 'K': ns = numericf; break;
	case 'l': case 'L': ns = stringf; break;
	case 'm': case 'M': ns = finf; break;
	case 'n': case 'N': ns = timef; break;
	default: ns = intro; break;
	}
    }
    FullUpdate++;
    (void) move(1,0);
    (void) clrtobot();
}

pscreen(screen)
char *screen[];
{
    int line;
    int dbline;

    (void) move(1,0);
    (void) clrtobot();
    dbline = 1;
    for (line = 0; screen[line]; line++) {
	(void) move(dbline++, 4);
	(void) addstr (screen[line]);
	(void) clrtoeol();
    }
    (void) move(0,0);
    (void) printw("Which Screen? [a-n, q]");
    (void) clrtoeol();
    (void) refresh();
    return(nmgetch());
}

Added interp.c.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
/*	SC	A Spreadsheet Calculator
 *		Expression interpreter and assorted support routines.
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel, 
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *		More mods by Alan Silverstein, 3-4/88, see list of changes.
 *		$Revision: 1.2 $
 */

#include <math.h>
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <regex.h>
#include <errno.h>

#ifdef BSD42
#include <strings.h>
#include <sys/time.h>
#ifndef strchr
#define strchr rindex
#endif
#else
#include <time.h>
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include <curses.h>
#include "sc.h"

#ifdef SIGVOID
    void quit();
#else
    int quit();
#endif

/* Use this structure to save the the last 'g' command */

struct go_save {
	int g_type;
	double g_n;
	char *g_s;
	int  g_row;
	int  g_col;
} gs;

/* g_type can be: */

#define G_NONE 0			/* Starting value - must be 0*/
#define G_NUM 1
#define G_STR 2
#define G_CELL 3

extern FILE *popen();

jmp_buf fpe_save;
int	exprerr;	   /* Set by eval() and seval() if expression errors */
double  prescale = 1.0;    /* Prescale for constants in let() */
int	extfunc  = 0;	   /* Enable/disable external functions */
int     loading = 0;       /* Set when readfile() is active */
double fn1_eval();
double fn2_eval();

#define PI (double)3.14159265358979323846
#define dtr(x) ((x)*(PI/(double)180.0))
#define rtd(x) ((x)*(180.0/(double)PI))

double finfunc(fun,v1,v2,v3)
int fun;
double v1,v2,v3;
{
 	double answer,p;
 
 	p = fn2_eval(pow, 1 + v2, v3);
 
 	switch(fun)
 	{
 	case PV:
 		answer = v1 * (1 - 1/p) / v2;
 		break;
 	case FV:
 		answer = v1 * (p - 1) / v2;
 		break;
 	case PMT:
 		answer = v1 * v2 / (1 - 1/p);
 		break;
	}
	return(answer);
}

char *
dostindex( val, minr, minc, maxr, maxc)
double val;
int minr, minc, maxr, maxc;
{
    register r,c;
    register struct ent *p;
    char *pr;
    int x;

    x = (int) val;
    r = minr; c = minc;
    p = 0;
    if ( minr == maxr ) { /* look along the row */
	c = minc + x - 1;
	if (c <= maxc && c >=minc)
	    p = tbl[r][c];
    } else if ( minc == maxc ) { /* look down the column */
	r = minr + x - 1;
	if (r <= maxr && r >=minr)
	    p = tbl[r][c];
    } else {
	error ("range specified to @stindex");
	return(0);
    }
    if (p && p->label) {
	pr = xmalloc((unsigned)(strlen(p->label)+1));
	(void)strcpy(pr, p->label);
	return (pr);
     } else
	return(0);
}

double
doindex( val, minr, minc, maxr, maxc)
double val;
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;
    int x;

    x = (int) val;
    v = 0;
    r = minr; c = minc;
    if ( minr == maxr ) { /* look along the row */
	c = minc + x - 1;
	if (c <= maxc && c >=minc 
		&& (p = tbl[r][c] ) && p->flags&is_valid )
					return p->v;
	}
    else if ( minc == maxc ){ /* look down the column */
	r = minr + x - 1;
	if (r <= maxr && r >=minr 
		&& (p = tbl[r][c] ) && p->flags&is_valid )
					return p->v;
	}
    else error(" range specified to @index");
    return v;
}

double
dolookupn( val, minr, minc, maxr, maxc, delta)
double val;
int minr, minc, maxr, maxc, delta;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 0;
    r = minr; c = minc;
    if ( minr == maxr ) { /* look along the row */
	for ( c = minc; c <= maxc; c++) {
		if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
			if(p->v <= val) {
				p = tbl[r+delta][c];
				if ( p && p->flags&is_valid)
					v = p->v;
				}
			else return v;
			}
		}
	}
    else if ( minc == maxc ){ /* look down the column */
	for ( r = minr; r <= maxr; r++) {
		if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
			if(p->v <= val) {
				p = tbl[r][c+delta];
				if ( p && p->flags&is_valid)
					v = p->v;
				}
			else return v;
			}
		}
	}
    else error(" range specified to @lookup");
    return v;
}

double
dolookups(s, minr, minc, maxr, maxc, delta)
char *s;
int minr, minc, maxr, maxc, delta;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 0;
    r = minr; c = minc;
    if ( minr == maxr ) { /* look along the row */
	for ( c = minc; c <= maxc; c++) {
	    if ( (p = tbl[r][c] ) && p->label) {
		if(strcmp(s,p->label) == 0) {
		    p = tbl[r+delta][c];
		    xfree(s);
		    if ( p && p->flags & is_valid)
			return(p->v);
		}
	    }
	}
    } else if ( minc == maxc ) { /* look down the column */
	for ( r = minr; r <= maxr; r++) {
	    if ( (p = tbl[r][c] ) && p->label) {
		if(strcmp(s,p->label) == 0) {
		    p = tbl[r][c+delta];
		    xfree(s);
		    if ( p && p->flags & is_valid)
			return(p->v);
		}
	    }
	}
    } else error(" range specified to @lookup");
    xfree(s);
    return v;
}

char *
dostlookupn(val, minr, minc, maxr, maxc, delta)
double val;
int minr, minc, maxr, maxc, delta;
{
    char *pr, *vp;
    register r,c;
    register struct ent *p;

    vp = pr = NULL;
    r = minr; c = minc;
    if ( minr == maxr ) { /* look along the row */
	for ( c = minc; c <= maxc; c++) {
	    if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
		if(p->v <= val) {
		    if((p = tbl[r+delta][c]) && p->label)
			vp = p->label;
		} else {
		    if (vp) {
			pr = xmalloc((unsigned)(strlen(vp)+1));
			(void)strcpy(pr, vp);
		    }
		    return pr;
		}
	    }
	}
    } else if ( minc == maxc ){ /* look down the column */
	for ( r = minr; r <= maxr; r++) {
	    if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
		if(p->v <= val) {
		    if((p = tbl[r][c+delta]) && p->label)
			vp = p->label;
		} else {
		    if (vp) {
			pr = xmalloc((unsigned)(strlen(vp)+1));
			(void)strcpy(pr,vp);
		    }
		    return pr;
		}
	    }
	}
    } else error(" range specified to @stlookup");
    return pr;
}

char *
dostlookups(s, minr, minc, maxr, maxc, delta)
char *s;
int minr, minc, maxr, maxc, delta;
{
    char *pr;
    register r,c;
    register struct ent *p;

    pr = NULL;
    r = minr; c = minc;
    if ( minr == maxr ) { /* look along the row */
	for ( c = minc; c <= maxc; c++) {
	    if ( (p = tbl[r][c] ) && p->label) {
		if(strcmp(s,p->label) == 0) {
		    if((p = tbl[r+delta][c]) && p->label) {
			xfree(s);
			pr = xmalloc((unsigned)strlen(p->label)+1);
			return(pr);
		    }
		}
	    }
	}
    } else if ( minc == maxc ) { /* look down the column */
	for ( r = minr; r <= maxr; r++) {
	    if ( (p = tbl[r][c] ) && p->label) {
		if(strcmp(s,p->label) == 0) {
		    if((p = tbl[r][c+delta]) && p->label) {
			xfree(s);
			pr = xmalloc((unsigned)strlen(p->label)+1);
			return(pr);
		    }
		}
	    }
	}
    } else error(" range specified to @stlookup");
    xfree(s);
    return pr;
}

double
dosum(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid)
		v += p->v;
    return v;
}

double
doprod(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 1;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid)
		v *= p->v;
    return v;
}

double
doavg(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c,count;
    register struct ent *p;

    v = 0;
    count = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid) {
		v += p->v;
		count++;
	    }

    if (count == 0) 
	return ((double) 0);

    return (v / (double)count);
}

double
dostddev(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double lp, rp, v, nd;
    register r,c,n;
    register struct ent *p;

    n = 0;
    lp = 0;
    rp = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid) {
		v = p->v;
		lp += v*v;
		rp += v;
		n++;
	    }

    if ((n == 0) || (n == 1)) 
	return ((double) 0);
    nd = (double)n;
    return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
}

double
domax(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c,count;
    register struct ent *p;

    count = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid) {
		if (!count) {
		    v = p->v;
		    count++;
		} else if (p->v > v)
		    v = p->v;
	    }

    if (count == 0) 
	return ((double) 0);

    return (v);
}

double
domin(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c,count;
    register struct ent *p;

    count = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid) {
		if (!count) {
		    v = p->v;
		    count++;
		} else if (p->v < v)
		    v = p->v;
	    }

    if (count == 0) 
	return ((double) 0);

    return (v);
}

double
dotime(which, when)
int which;
double when;
{
	long time();

	static long t_cache;
	static struct tm *tp;
	long tloc;

	if (which == NOW) 
	    return (double)time((long *)0);

	tloc = (long)when;

	if (tloc != t_cache) {
	    tp = localtime(&tloc);
	    tp->tm_mon += 1;
	    tp->tm_year += 1900;
	    t_cache = tloc;
	}

	switch (which) {
		case HOUR: return((double)(tp->tm_hour));
		case MINUTE: return((double)(tp->tm_min));
		case SECOND: return((double)(tp->tm_sec));
		case MONTH: return((double)(tp->tm_mon));
		case DAY: return((double)(tp->tm_mday));
		case YEAR: return((double)(tp->tm_year));
	}
	/* Safety net */
	return (0.0);
}

double
doston(s)
char *s;
{
    char *strtof();
    double v;

    if (!s)
	return((double)0.0);

    (void)strtof(s, &v);
    xfree(s);
    return(v);
}

double
doeqs(s1, s2)
char *s1, *s2;
{
    double v;

    if (!s1 && !s2)
	return(1.0);

    if (!s1 || !s2)
	v = 0.0;
    else if (strcmp(s1, s2) == 0)
	v = 1.0;
    else
	v = 0.0;

    if (s1)
    	xfree(s1);

    if (s2)
    	xfree(s2);

    return(v);
}


/*
 * Given a string representing a column name and a value which is a column
 * number, return a pointer to the selected cell's entry, if any, else 0.  Use
 * only the integer part of the column number.  Always free the string.
 */

struct ent *
getent (colstr, rowdoub)
    char *colstr;
    double rowdoub;
{
    int collen;		/* length of string */
    int row, col;	/* integer values   */
    struct ent *ep = 0;	/* selected entry   */

    if (((row = (int) floor (rowdoub)) >= 0)
     && (row < MAXROWS)				/* in range */
     && ((collen = strlen (colstr)) <= 2)	/* not too long */
     && ((col = atocol (colstr, collen)) >= 0)
     && (col < MAXCOLS))			/* in range */
    {
	ep = tbl [row] [col];
    }

    xfree (colstr);
    return (ep);
}


/*
 * Given a string representing a column name and a value which is a column
 * number, return the selected cell's numeric value, if any.
 */

double
donval (colstr, rowdoub)
    char *colstr;
    double rowdoub;
{
    struct ent *ep;

    return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
	    (ep -> v) : 0);
}


/*
 *	The list routines (e.g. dolmax) are called with an LMAX enode.
 *	The left pointer is a chain of ELIST nodes, the right pointer
 *	is a value.
 */
double
dolmax(ep)
struct enode *ep;
{
	register int count = 0;
	register double maxval = 0; /* Assignment to shut up lint */
	register struct enode *p;
	register double v;

	for (p = ep; p; p = p->e.o.left) {
		v = eval(p->e.o.right);
		if (!count || v > maxval) {
			maxval = v; count++;
		}
	}
	if (count) return maxval;
	else return 0.0;
}

double
dolmin(ep)
struct enode *ep;
{
	register int count = 0;
	register double minval = 0; /* Assignment to shut up lint */
	register struct enode *p;
	register double v;

	for (p = ep; p; p = p->e.o.left) {
		v = eval(p->e.o.right);
		if (!count || v < minval) {
			minval = v; count++;
		}
	}
	if (count) return minval;
	else return 0.0;
}

double 
eval(e)
register struct enode *e;
{
    register r,c, delta;
    register maxr, maxc;
    register minr, minc;
    register struct enode *el;

    if (e==0) return 0;
    switch (e->op) {
	case '+':	return (eval(e->e.o.left) + eval(e->e.o.right));
	case '-':	return (eval(e->e.o.left) - eval(e->e.o.right));
	case '*':	return (eval(e->e.o.left) * eval(e->e.o.right));
	case '/':     	return (eval(e->e.o.left) / eval(e->e.o.right));
	case '%':     {	double num, denom;
			num = floor(eval(e->e.o.left));
			denom = floor(eval (e->e.o.right));
			return denom ? num - floor(num/denom)*denom : 0; }
	case '^':	return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
	case '<':	return (eval(e->e.o.left) < eval(e->e.o.right));
	case '=':	return (eval(e->e.o.left) == eval(e->e.o.right));
	case '>':	return (eval(e->e.o.left) > eval(e->e.o.right));
	case '&':	return (eval(e->e.o.left) && eval(e->e.o.right));
	case '|':	return (eval(e->e.o.left) || eval(e->e.o.right));
	case '?':	return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
						: eval(e->e.o.right->e.o.right);
	case 'm':	return (-eval(e->e.o.right));
	case 'f':	return (eval(e->e.o.right));
	case '~':	return (eval(e->e.o.right) == 0.0);
	case 'k':	return (e->e.k);
	case 'v':	return (e->e.v.vp->v);
	case INDEX:
	  {
	      maxr = el->e.o.left->e.r.right.vp -> row;
	      maxc = el->e.o.left->e.r.right.vp -> col;
	      minr = el->e.o.left->e.r.left.vp -> row;
	      minc = el->e.o.left->e.r.left.vp -> col;
	      if (minr>maxr) r = maxr, maxr = minr, minr = r;
	      if (minc>maxc) c = maxc, maxc = minc, minc = c;
	      return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
	  }
	case LOOKUP:
	  {
	      /*
	       * lookup -> elist -> expression for delta rows/cols
	       *   |         |
	       *   |         v
	       *   |   Reduce|Lookup with range specification
	       *   v
	       *  expression to lookup
	       */

	      el = e->e.o.right;
	      maxr = el->e.o.left->e.r.right.vp -> row;
	      maxc = el->e.o.left->e.r.right.vp -> col;
	      minr = el->e.o.left->e.r.left.vp -> row;
	      minc = el->e.o.left->e.r.left.vp -> col;
	      delta = (int) eval(el->e.o.right);
	      if (minr>maxr) r = maxr, maxr = minr, minr = r;
	      if (minc>maxc) c = maxc, maxc = minc, minc = c;
	      if (etype(e->e.o.left) == NUM)
		  return dolookupn(eval(e->e.o.left),
				   minr, minc, maxr, maxc, delta);
	      else
		  return dolookups(seval(e->e.o.left),
				   minr, minc, maxr, maxc, delta);
	  }
	case REDUCE | '+':
 	case REDUCE | '*':
 	case REDUCE | 'a':
 	case REDUCE | 's':
	case REDUCE | MAX:
	case REDUCE | MIN:
	    {	register r,c;
		register maxr, maxc;
		register minr, minc;
		maxr = e->e.r.right.vp -> row;
		maxc = e->e.r.right.vp -> col;
		minr = e->e.r.left.vp -> row;
		minc = e->e.r.left.vp -> col;
		if (minr>maxr) r = maxr, maxr = minr, minr = r;
		if (minc>maxc) c = maxc, maxc = minc, minc = c;
	        switch (e->op) {
	            case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
 	            case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
 	            case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
 	            case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
 	            case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
 	            case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
		}
	    }
	case ACOS:	 return (fn1_eval( acos, eval(e->e.o.right)));
	case ASIN:	 return (fn1_eval( asin, eval(e->e.o.right)));
	case ATAN:	 return (fn1_eval( atan, eval(e->e.o.right)));
	case ATAN2:	 return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
	case CEIL:	 return (fn1_eval( ceil, eval(e->e.o.right)));
	case COS:	 return (fn1_eval( cos, eval(e->e.o.right)));
	case EXP:	 return (fn1_eval( exp, eval(e->e.o.right)));
	case FABS:	 return (fn1_eval( fabs, eval(e->e.o.right)));
	case FLOOR:	 return (fn1_eval( floor, eval(e->e.o.right)));
	case HYPOT:	 return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
	case LOG:	 return (fn1_eval( log, eval(e->e.o.right)));
	case LOG10:	 return (fn1_eval( log10, eval(e->e.o.right)));
	case POW:	 return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
	case SIN:	 return (fn1_eval( sin, eval(e->e.o.right)));
	case SQRT:	 return (fn1_eval( sqrt, eval(e->e.o.right)));
	case TAN:	 return (fn1_eval( tan, eval(e->e.o.right)));
	case DTR:	 return (dtr(eval(e->e.o.right)));
	case RTD:	 return (rtd(eval(e->e.o.right)));
	case RND:	 {
			    double temp;
			    temp = eval(e->e.o.right);
			    return(temp-floor(temp) < 0.5 ?
					     floor(temp) : ceil(temp));
			 }
	case FV:
	case PV:
	case PMT:	return(finfunc(e->op,eval(e->e.o.left),
				   eval(e->e.o.right->e.o.left),
				      eval(e->e.o.right->e.o.right)));
	case HOUR:	 return (dotime(HOUR, eval(e->e.o.right)));
	case MINUTE:	 return (dotime(MINUTE, eval(e->e.o.right)));
	case SECOND:	 return (dotime(SECOND, eval(e->e.o.right)));
	case MONTH:	 return (dotime(MONTH, eval(e->e.o.right)));
	case DAY:	 return (dotime(DAY, eval(e->e.o.right)));
	case YEAR:	 return (dotime(YEAR, eval(e->e.o.right)));
	case NOW:	 return (dotime(NOW, (double)0.0));
	case STON:	 return (doston(seval(e->e.o.right)));
	case EQS:        return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
	case LMAX:	 return dolmax(e);
	case LMIN:	 return dolmin(e);
	case NVAL:       return (donval(seval(e->e.o.left),eval(e->e.o.right)));
	default:	 error ("Illegal numeric expression");
			 exprerr = 1;
			 return((double)0.0);
    }
#ifdef sequent
    return((double)0.0);	/* Quiet a questionable compiler complaint */
#endif
}

#ifdef SIGVOID
void
#endif
eval_fpe() /* Trap for FPE errors in eval */
{
	longjmp(fpe_save, 1);
}

double fn1_eval(fn, arg)
double (*fn)();
double arg;
{
	double res;
	errno = 0;
	res = (*fn)(arg);
	if(errno)
	  eval_fpe();

	return res;
}

double fn2_eval(fn, arg1, arg2)
double (*fn)();
double arg1, arg2;
{
	double res;
	errno = 0;
	res = (*fn)(arg1, arg2);
	if(errno) 
	    eval_fpe();

	return res;
}

/* 
 * Rules for string functions:
 * Take string arguments which they xfree.
 * All returned strings are assumed to be xalloced.
 */

char *
docat(s1, s2)
register char *s1, *s2;
{
    register char *p;
    char *arg1, *arg2;

    if (!s1 && !s2)
	return(0);
    arg1 = s1 ? s1 : "";
    arg2 = s2 ? s2 : "";
    p = xmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
    (void) strcpy(p, arg1);
    (void) strcat(p, arg2);
    if (s1)
        xfree(s1);
    if (s2)
        xfree(s2);
    return(p);
}

char *
dodate(tloc)
long tloc;
{
    char *tp;
    char *p;

    tp = ctime(&tloc);
    tp[24] = 0;
    p = xmalloc((unsigned)25);
    (void) strcpy(p, tp);
    return(p);
}


char *
dofmt(fmtstr, v)
char *fmtstr;
double v;
{
    char buff[1024];
    char *p;

    if (!fmtstr)
	return(0);
    (void)sprintf(buff, fmtstr, v);
    p = xmalloc((unsigned)(strlen(buff)+1));
    (void) strcpy(p, buff);
    xfree(fmtstr);
    return(p);
}


/*
 * Given a command name and a value, run the command with the given value and
 * read and return its first output line (only) as an allocated string, always
 * a copy of prevstr, which is set appropriately first unless external
 * functions are disabled, in which case the previous value is used.  The
 * handling of prevstr and freeing of command is tricky.  Returning an
 * allocated string in all cases, even if null, insures cell expressions are
 * written to files, etc.
 */

#ifdef VMS
char *
doext(command, value)
char *command;
double value;
{
    error("Warning: External functions unavailable on VMS");
    if (command)
	xfree(command);
    return (strcpy (xmalloc((unsigned) 1), "\0"));
}

#else /* VMS */

char *
doext (command, value)
char   *command;
double value;
{
    static char *prevstr = 0;	/* previous result */
    char buff[1024];		/* command line/return, not permanently alloc */

    if (!prevstr) {
	prevstr = xmalloc((unsigned)1);
	*prevstr = 0;
    }
    if (!extfunc)    {
	error ("Warning: external functions disabled; using %s value",
		prevstr ? "previous" : "null");

	if (command) xfree (command);
    } else {
	if (prevstr) xfree (prevstr);		/* no longer needed */
	prevstr = 0;

	if ((! command) || (! *command)) {
	    error ("Warning: external function given null command name");
	    if (command) xfree (command);
	} else {
	    FILE *pp;

	    (void) sprintf (buff, "%s %g", command, value); /* build cmd line */
	    xfree (command);

	    error ("Running external function...");
	    (void) refresh();

	    if ((pp = popen (buff, "r")) == (FILE *) NULL)	/* run it */
		error ("Warning: running \"%s\" failed", buff);
	    else {
		if (fgets (buff, 1024, pp) == NULL)	/* one line */
		    error ("Warning: external function returned nothing");
		else {
		    char *cp;

		    error ("");				/* erase notice */
		    buff[1023] = 0;

		    if (cp = strchr (buff, '\n'))	/* contains newline */
			*cp = 0;			/* end string there */

		    (void) strcpy (prevstr = 
			 xmalloc ((unsigned) (strlen (buff) + 1)), buff);
			 /* save alloc'd copy */
		}
		(void) pclose (pp);

	    } /* else */
	} /* else */
    } /* else */
    return (strcpy (xmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
}

#endif /* VMS */


/*
 * Given a string representing a column name and a value which is a column
 * number, return the selected cell's string value, if any.  Even if none,
 * still allocate and return a null string so the cell has a label value so
 * the expression is saved in a file, etc.
 */

char *
dosval (colstr, rowdoub)
    char *colstr;
    double rowdoub;
{
    struct ent *ep;
    char *label;

    label = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
    return (strcpy (xmalloc ((unsigned) (strlen (label) + 1)), label));
}


/*
 * Substring:  Note that v1 and v2 are one-based to users, but zero-based
 * when calling this routine.
 */

char *
dosubstr(s, v1, v2)
char *s;
register int v1,v2;
{
    register char *s1, *s2;
    char *p;

    if (!s)
	return(0);

    if (v2 >= strlen (s))		/* past end */
	v2 =  strlen (s) - 1;		/* to end   */

    if (v1 < 0 || v1 > v2) {		/* out of range, return null string */
	xfree(s);
	p = xmalloc((unsigned)1);
	p[0] = 0;
	return(p);
    }
    s2 = p = xmalloc((unsigned)(v2-v1+2));
    s1 = &s[v1];
    for(; v1 <= v2; s1++, s2++, v1++)
	*s2 = *s1;
    *s2 = 0;
    xfree(s);
    return(p);
}

char *
seval(se)
register struct enode *se;
{
    register char *p;
    register r,c,delta;
    register maxr, maxc;
    register minr, minc;
    register struct enode *el;

    if (se==0) return 0;
    switch (se->op) {
	case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
		     (void) strcpy(p, se->e.s);
		     return(p);
	case O_VAR:    {
			struct ent *ep;
			ep = se->e.v.vp;

			if (!ep->label)
			    return(0);
			p = xmalloc((unsigned)(strlen(ep->label)+1));
			(void) strcpy(p, ep->label);
			return(p);
		     }
	case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
	case 'f':    return(seval(se->e.o.right));
	case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
					     : seval(se->e.o.right->e.o.right));
	case DATE:   return(dodate((long)(eval(se->e.o.right))));
	case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
 	case STINDEX:
	  {
	      maxr = se->e.o.right->e.r.right.vp -> row;
	      maxc = se->e.o.right->e.r.right.vp -> col;
	      minr = se->e.o.right->e.r.left.vp -> row;
	      minc = se->e.o.right->e.r.left.vp -> col;
	      if (minr>maxr) r = maxr, maxr = minr, minr = r;
	      if (minc>maxc) c = maxc, maxc = minc, minc = c;
	      return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
	  }
	case STLOOKUP:
	  {
	      /*
	       * stlookup -> elist -> expression for delta rows/cols
	       *   |         |
	       *   |	     v
	       *   |   Reduce|StLookup with range specification
	       *   v
	       *  expression to lookup
	       */

	      el = se->e.o.right;
	      maxr = el->e.o.left->e.r.right.vp -> row;
	      maxc = el->e.o.left->e.r.right.vp -> col;
	      minr = el->e.o.left->e.r.left.vp -> row;
	      minc = el->e.o.left->e.r.left.vp -> col;
	      delta = (int) eval(el->e.o.right);
	      if (minr>maxr) r = maxr, maxr = minr, minr = r;
	      if (minc>maxc) c = maxc, maxc = minc, minc = c;
	      if (etype(se->e.o.left) == NUM)
		  return dostlookupn(eval(se->e.o.left),
				   minr, minc, maxr, maxc, delta);
	      else
		  return dostlookups(seval(se->e.o.left),
				   minr, minc, maxr, maxc, delta);
	  }
	case EXT:    return(doext(seval(se->e.o.left), eval(se->e.o.right)));
	case SVAL:   return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
	case SUBSTR: return(dosubstr(seval(se->e.o.left),
			    (int)eval(se->e.o.right->e.o.left) - 1,
			    (int)eval(se->e.o.right->e.o.right) - 1));
	default:
		     error ("Illegal string expression");
		     exprerr = 1;
		     return(0);
	}
}

/*
 * The graph formed by cell expressions which use other cells's values is not
 * evaluated "bottom up".  The whole table is merely re-evaluated cell by cell,
 * top to bottom, left to right, in RealEvalAll().  Each cell's expression uses
 * constants in other cells.  However, RealEvalAll() notices when a cell gets a
 * new numeric or string value, and reports if this happens for any cell.
 * EvalAll() repeats calling RealEvalAll() until there are no changes or the
 * evaluation count expires.
 */

int propagation = 10;	/* max number of times to try calculation */

setiterations(i)
	int i;
	{
	if(i<1){
		error("iteration count must be at least 1");
		propagation = 1;
		}
	else propagation = i;
	}

EvalAll () {
      int lastcnt, repct = 0;
  
     while ((lastcnt = RealEvalAll()) && (repct++ <= propagation));
     if((propagation>1)&& (lastcnt >0 ))
 	    error("Still changing after %d iterations",propagation-1);
}

/*
 * Evaluate all cells which have expressions and alter their numeric or string
 * values.  Return the number of cells which changed.
 */

int 
RealEvalAll () {
    register int i,j;
    int chgct = 0;
    register struct ent *p;

    (void) signal(SIGFPE, eval_fpe);
    if(calc_order == BYROWS ) {
    for (i=0; i<=maxrow; i++)
  	for (j=0; j<=maxcol; j++)
 	    if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
    }
    else if ( calc_order == BYCOLS ) {
    for (j=0; j<=maxcol; j++)
 	for (i=0; i<=maxrow; i++)
 	    if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
    }
    else error("Internal error calc_order");
 
    (void) signal(SIGFPE, quit);
    return(chgct);
}

RealEvalOne(p, i , j, chgct)
register struct ent *p;
int i, j, *chgct;
{
	if (p->flags & is_strexpr) {
	    char *v;
	    if (setjmp(fpe_save)) {
		error("Floating point exception %s", v_name( i, j));
		v = "";
	    } else {
		v = seval(p->expr);
	    }
	    if (!v && !p->label) /* Everything's fine */
		return;
	    if (!p->label || !v || strcmp(v, p->label) != 0) {
		(*chgct)++;
		p->flags |= is_changed;
	    }
	    if(p->label)
		xfree(p->label);
	    p->label = v;
	} else {
	    double v;
	    if (setjmp(fpe_save)) {
		error("Floating point exception %s", v_name( i, j));
		v = 0.0;
	    } else {
		v = eval (p->expr);
	    }
	    if (v != p->v) {
		p->v = v; (*chgct)++;
		p->flags |= is_changed|is_valid;
	    }
	}
}

struct enode *
new(op, a1, a2)
struct enode *a1, *a2;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.o.left = a1;
    p->e.o.right = a2;
    return p;
}

struct enode *
new_var(op, a1)
struct ent_ptr a1;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.v = a1;
    return p;
}

struct enode *
new_range(op, a1)
struct range_s a1;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.r = a1;
    return p;
}

struct enode *
new_const(op, a1)
double a1;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.k = a1;
    return p;
}

struct enode *
new_str(s)
char *s;
{
    register struct enode *p;

    p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
    p->op = O_SCONST;
    p->e.s = s;
    return(p);
}

copy(dv1, dv2, v1, v2)
struct ent *dv1, *dv2, *v1, *v2;
{
    int minsr, minsc;
    int maxsr, maxsc;
    int mindr, mindc;
    int maxdr, maxdc;
    int vr, vc;
    int r, c;

    mindr = dv1->row;
    mindc = dv1->col;
    maxdr = dv2->row;
    maxdc = dv2->col;
    if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
    if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
    maxsr = v2->row;
    maxsc = v2->col;
    minsr = v1->row;
    minsc = v1->col;
    if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
    if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
    if (maxdr >= MAXROWS  || 
           maxdc >= MAXCOLS) {
	error ("The table can't be any bigger");
	return;
    }
    erase_area(mindr, mindc, maxdr, maxdc);
    if (minsr == maxsr && minsc == maxsc) {
	/* Source is a single cell */
	for(vr = mindr; vr <= maxdr; vr++)
	    for (vc = mindc; vc <= maxdc; vc++)
		copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
    } else if (minsr == maxsr) {
	/* Source is a single row */
	for (vr = mindr; vr <= maxdr; vr++)
	    copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
    } else if (minsc == maxsc) {
	/* Source is a single column */
	for (vc = mindc; vc <= maxdc; vc++)
	    copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
    } else {
	/* Everything else */
	copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
    }
    sync_refs();
}

copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
int vr, vc, minsr, minsc, maxsr, maxsc;
{
    register struct ent *p;
    register struct ent *n;
    register int sr, sc;
    register int dr, dc;

    for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
	for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
	    n = lookat (dr, dc);
	    (void) clearent(n);
	    if (p = tbl[sr][sc])
		copyent( n, p, dr - sr, dc - sc);
	}
}

eraser(v1, v2)
struct ent *v1, *v2;
{
	FullUpdate++;
	flush_saved();
	erase_area(v1->row, v1->col, v2->row, v2->col);
	sync_refs();
}

/* Goto subroutines */

g_free()
{
    switch (gs.g_type) {
    case G_STR: xfree(gs.g_s); break;
    default: break;
    }
    gs.g_type = G_NONE;
}

go_last()
{
    switch (gs.g_type) {
    case G_NONE:
		error("Nothing to repeat"); break;
    case G_NUM:
		num_search(gs.g_n);
		break;
    case  G_CELL:
		moveto(gs.g_row, gs.g_col);
	    	break;
    case  G_STR: 
		gs.g_type = G_NONE;	/* Don't free the string */
   	    	str_search(gs.g_s); 
	   	break;

    default: error("go_last: internal error");
    }
}

moveto(row, col)
int row, col;
{
    currow = row;
    curcol = col;
    g_free();
    gs.g_type = G_CELL;
    gs.g_row = currow;
    gs.g_col = curcol;
}

num_search(n)
double n;
{
    register struct ent *p;
    register int r,c;

    g_free();
    gs.g_type = G_NUM;
    gs.g_n = n;

    r = currow;
    c = curcol;
    do {
	if (c < maxcol)
	    c++;
	else {
	    if (r < maxrow) {
		while(++r < maxrow && row_hidden[r]) /* */;
		c = 0;
	    } else {
		r = 0;
		c = 0;
	    }
	}
	if (r == currow && c == curcol) {
	    error("Number not found");
	    return;
	}
	p = tbl[r][c];
    } while(col_hidden[c] || !p || p && (!(p->flags & is_valid) 
                                        || (p->flags&is_valid) && p->v != n));
    currow = r;
    curcol = c;
}


str_search(s)
char *s;
{
    struct ent *p;
    int r, c;
    regex_t tmp;

    if (regcomp(&tmp, s, REG_NOSUB) != 0) {
	error("Invalid search string");
	return;
    }
    g_free();
    gs.g_type = G_STR;
    gs.g_s = s;
    r = currow;
    c = curcol;
    do {
	if (c < maxcol)
	    c++;
	else {
	    if (r < maxrow) {
		while(++r < maxrow && row_hidden[r]) /* */;
		c = 0;
	    } else {
		r = 0;
		c = 0;
	    }
	}
	if (r == currow && c == curcol) {
	    error("String not found");
	    regfree(&tmp);
	    return;
	}
	p = tbl[r][c];
    } while(col_hidden[c] || !p || p && (!(p->label) 
		       || (regexec(&tmp, p->label, 0, 0, 0) != 0)));
    currow = r;
    curcol = c;
    regfree(&tmp);
}

fill (v1, v2, start, inc)
struct ent *v1, *v2;
double start, inc;
{
    register r,c;
    register struct ent *n;
    int maxr, maxc;
    int minr, minc;

    maxr = v2->row;
    maxc = v2->col;
    minr = v1->row;
    minc = v1->col;
    if (minr>maxr) r = maxr, maxr = minr, minr = r;
    if (minc>maxc) c = maxc, maxc = minc, minc = c;
    if (maxr >= MAXROWS) maxr = MAXROWS-1;
    if (maxc >= MAXCOLS) maxc = MAXCOLS-1;
    if (minr < 0) minr = 0;
    if (minr < 0) minr = 0;

    FullUpdate++;
    if( calc_order == BYROWS ) {
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++) {
	    n = lookat (r, c);
	    (void) clearent(n);
	    n->v = start;
	    start += inc;
	    n->flags |= (is_changed|is_valid);
	}
    }
    else if ( calc_order == BYCOLS ) {
    for (c = minc; c<=maxc; c++)
	for (r = minr; r<=maxr; r++) {
	    n = lookat (r, c);
	    (void) clearent(n);
	    n->v = start;
	    start += inc;
	    n->flags |= (is_changed|is_valid);
	}
    }
    else error(" Internal error calc_order");
}

let (v, e)
struct ent *v;
struct enode *e;
{
    double val;

    exprerr = 0;
    (void) signal(SIGFPE, eval_fpe);
    if (setjmp(fpe_save)) {
	error ("Floating point exception in cell %s", v_name(v->row, v->col));
	val = 0.0;
    } else {
	val = eval(e);
    }
    (void) signal(SIGFPE, quit);
    if (exprerr) {
	efree(e);
	return;
    }
    if (constant(e)) {
	if (!loading)
	    v->v = val * prescale;
	else
	    v->v = val;
	if (!(v->flags & is_strexpr)) {
            efree (v->expr);
	    v->expr = 0;
	}
	efree(e);
        v->flags |= (is_changed|is_valid);
        changed++;
        modflg++;
	return;
    }
    efree (v->expr);
    v->expr = e;
    v->flags |= (is_changed|is_valid);
    v->flags &= ~is_strexpr;
    changed++;
    modflg++;
}

slet (v, se, flushdir)
struct ent *v;
struct enode *se;
int flushdir;
{
    char *p;

    exprerr = 0;
    (void) signal(SIGFPE, eval_fpe);
    if (setjmp(fpe_save)) {
	error ("Floating point exception in cell %s", v_name(v->row, v->col));
	p = "";
    } else {
	p = seval(se);
    }
    (void) signal(SIGFPE, quit);
    if (exprerr) {
	efree(se);
	return;
    }
    if (constant(se)) {
	label(v, p, flushdir);
	if (p)
	    xfree(p);
	efree(se);
	if (v->flags & is_strexpr) {
            efree (v->expr);
	    v->expr = 0;
	    v->flags &= ~is_strexpr;
	}
	return;
    }
    efree (v->expr);
    v->expr = se;
    v->flags |= (is_changed|is_strexpr);
    if (flushdir<0) v->flags |= is_leftflush;
    else v->flags &= ~is_leftflush;
    FullUpdate++;
    changed++;
    modflg++;
}

hide_row(arg)
int arg;
{
    if (arg < 0) {
	error("Invalid Range");
	return;
    }
    if (arg > MAXROWS-2) {
	error("You can't hide the last row");
	return;
    }
    FullUpdate++;
    row_hidden[arg] = 1;
}

hide_col(arg)
int arg;
{
    if (arg < 0) {
	error("Invalid Range");
	return;
    }
    if (arg > MAXCOLS-2) {
	error("You can't hide the last col");
	return;
    }
    FullUpdate++;
    col_hidden[arg] = 1;
}

clearent (v)
struct ent *v;
{
    if (!v)
	return;
    label(v,"",-1);
    v->v = 0;
    if (v->expr)
	efree(v->expr);
    v->expr = 0;
    v->flags |= (is_changed);
    v->flags &= ~(is_valid);
    changed++;
    modflg++;
}

/*
 * Say if an expression is a constant (return 1) or not.
 */

constant (e)
    register struct enode *e;
{
    return ((e == 0)
	 || ((e -> op) == O_CONST)
	 || ((e -> op) == O_SCONST)
	 || (((e -> op) != O_VAR)
	  && (((e -> op) & REDUCE) != REDUCE)
	  && constant (e -> e.o.left)
	  && constant (e -> e.o.right)
	  && (e -> op != EXT)	 /* functions look like constants but aren't */
	  && (e -> op != NVAL)
	  && (e -> op != SVAL)
	  && (e -> op != NOW)));
}

efree (e)
register struct enode *e;
{
    if (e) {
	if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
		&& (e->op & REDUCE) != REDUCE) {
	    efree(e->e.o.left);
	    efree(e->e.o.right);
	}
	if (e->op == O_SCONST && e->e.s)
	    xfree(e->e.s);
	xfree ((char *)e);
    }
}

label (v, s, flushdir)
register struct ent *v;
register char *s;
{
    if (v) {
	if (flushdir==0 && v->flags&is_valid) {
	    register struct ent *tv;
	    if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
		v = tv, flushdir = 1;
	    else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
		v = tv, flushdir = -1;
	    else flushdir = -1;
	}
	if (v->label) xfree((char *)(v->label));
	if (s && s[0]) {
	    v->label = xmalloc ((unsigned)(strlen(s)+1));
	    (void) strcpy (v->label, s);
	} else
	    v->label = 0;
	if (flushdir<0) v->flags |= is_leftflush;
	else v->flags &= ~is_leftflush;
	FullUpdate++;
	modflg++;
    }
}

decodev (v)
struct ent_ptr v; 
{
	register struct range *r;

	if (!v.vp) (void)sprintf (line+linelim,"VAR?");
	else if (r = find_range((char *)0, 0, v.vp, v.vp))
	    (void)sprintf(line+linelim, "%s", r->r_name);
	else
	    (void)sprintf (line+linelim, "%s%s%s%d",
			v.vf & FIX_COL ? "$" : "",
			coltoa(v.vp->col),
			v.vf & FIX_ROW ? "$" : "",
			v.vp->row);
	linelim += strlen (line+linelim);
}

char *
coltoa(col)
int col;
{
    static char rname[3];
    register char *p = rname;

    if (col > 25) {
	*p++ = col/26 + 'A' - 1;
	col %= 26;
    }
    *p++ = col+'A';
    *p = 0;
    return(rname);
}

/*
 *	To make list elements come out in the same order
 *	they were entered, we must do a depth-first eval
 *	of the ELIST tree
 */

static
decompile_list(p)
struct enode *p;
{
	if (!p) return;
	decompile_list(p->e.o.left);	/* depth first */
        decompile(p->e.o.right, 0);
	line[linelim++] = ',';
}

decompile(e, priority)
register struct enode *e;
{
    register char *s;
    if (e) {
	int mypriority;
	switch (e->op) {
	default: mypriority = 99; break;
	case '?': mypriority = 1; break;
	case ':': mypriority = 2; break;
	case '|': mypriority = 3; break;
	case '&': mypriority = 4; break;
	case '<': case '=': case '>': mypriority = 6; break;
	case '+': case '-': case '#': mypriority = 8; break;
	case '*': case '/': case '%': mypriority = 10; break;
	case '^': mypriority = 12; break;
	}
	if (mypriority<priority) line[linelim++] = '(';
	switch (e->op) {
	case 'f':	for (s="fixed "; line[linelim++] = *s++;);
			linelim--;
			decompile (e->e.o.right, 30);
			break;
	case 'm':	line[linelim++] = '-';
			decompile (e->e.o.right, 30);
			break;
	case '~':	line[linelim++] = '~';
			decompile (e->e.o.right, 30);
			break;
	case 'v':	decodev (e->e.v);
			break;
	case 'k':	(void)sprintf (line+linelim,"%.15g",e->e.k);
			linelim += strlen (line+linelim);
			break;
	case '$':	(void)sprintf (line+linelim, "\"%s\"", e->e.s);
			linelim += strlen(line+linelim);
			break;

	case REDUCE | '+': range_arg( "@sum(", e); break;
	case REDUCE | '*': range_arg( "@prod(", e); break;
	case REDUCE | 'a': range_arg( "@avg(", e); break;
	case REDUCE | 's': range_arg( "@stddev(", e); break;
	case REDUCE | MAX: range_arg( "@max(", e); break;
	case REDUCE | MIN: range_arg( "@min(", e); break;

	case ACOS:	one_arg( "@acos(", e); break;
	case ASIN:	one_arg( "@asin(", e); break;
	case ATAN:	one_arg( "@atan(", e); break;
	case ATAN2:	two_arg( "@atan2(", e); break;
	case CEIL:	one_arg( "@ceil(", e); break;
	case COS:	one_arg( "@cos(", e); break;
	case EXP:	one_arg( "@exp(", e); break;
	case FABS:	one_arg( "@fabs(", e); break;
	case FLOOR:	one_arg( "@floor(", e); break;
	case HYPOT:	two_arg( "@hypot(", e); break;
	case LOG:	one_arg( "@ln(", e); break;
	case LOG10:	one_arg( "@log(", e); break;
	case POW:	two_arg( "@pow(", e); break;
	case SIN:	one_arg( "@sin(", e); break;
	case SQRT:	one_arg( "@sqrt(", e); break;
	case TAN:	one_arg( "@tan(", e); break;
	case DTR:	one_arg( "@dtr(", e); break;
	case RTD:	one_arg( "@rtd(", e); break;
	case RND:	one_arg( "@rnd(", e); break;
	case HOUR:	one_arg( "@hour(", e); break;
	case MINUTE:	one_arg( "@minute(", e); break;
	case SECOND:	one_arg( "@second(", e); break;
	case MONTH:	one_arg( "@month(", e); break;
	case DAY:	one_arg( "@day(", e); break;
	case YEAR:	one_arg( "@year(", e); break;
	case DATE:	one_arg( "@date(", e); break;
	case STON:	one_arg( "@ston(", e); break;
	case FMT:	two_arg( "@fmt(", e); break;
	case EQS:	two_arg( "@eqs(", e); break;
	case NOW:	for ( s = "@now"; line[linelim++] = *s++;);
			linelim--;
			break;
	case LMAX:	list_arg("@max(", e); break;
	case LMIN: 	list_arg("@min(", e); break;
	case FV:	three_arg("@fv(", e); break;
	case PV:	three_arg("@pv(", e); break;
	case PMT:	three_arg("@pmt(", e); break;
	case NVAL:	two_arg("@nval(", e); break;
	case SVAL:	two_arg("@sval(", e); break;
	case EXT:	two_arg("@ext(", e); break;
	case SUBSTR:	three_arg("@substr(", e); break;
	case STINDEX:	index_arg("@stindex(", e); break;
	case INDEX:	index_arg("@index(", e); break;
	case LOOKUP:	lookup_arg("@lookup(", e); break;
	case STLOOKUP:	lookup_arg("@stlookup(", e); break;

	default:	decompile (e->e.o.left, mypriority);
			line[linelim++] = e->op;
			decompile (e->e.o.right, mypriority+1);
			break;

	}
	if (mypriority<priority) line[linelim++] = ')';
    } else line[linelim++] = '?';
}

index_arg(s, e)
char *s;
struct enode *e;
{
    for (; line[linelim++] = *s++;);
    linelim--;
    decompile( e-> e.o.left, 0 );
    range_arg(", ", e->e.o.right);
}

lookup_arg(s, e)
char *s;
struct enode *e;
{
    for (; line[linelim++] = *s++;);
    linelim--;
    decompile( e-> e.o.left, 0 );
    range_arg(", ", e->e.o.right->e.o.left);
    linelim--;
    one_arg(", ", e->e.o.right);
    line[linelim - 1] = ')';
}

list_arg(s, e)
char *s;
struct enode *e;
{
    for (; line[linelim++] = *s++;);
    linelim--;

    decompile (e->e.o.right, 0);
    line[linelim++] = ',';
    decompile_list(e->e.o.left);
    line[linelim - 1] = ')';
}

one_arg(s, e)
char *s;
struct enode *e;
{
    for (; line[linelim++] = *s++;);
    linelim--;
    decompile (e->e.o.right, 0);
    line[linelim++] = ')';
}

two_arg(s,e)
char *s;
struct enode *e;
{
    for (; line[linelim++] = *s++;);
    linelim--;
    decompile (e->e.o.left, 0);
    line[linelim++] = ',';
    decompile (e->e.o.right, 0);
    line[linelim++] = ')';
}

three_arg(s,e)
char *s;
struct enode *e;
{
    for (; line[linelim++] = *s++;);
    linelim--;
    decompile (e->e.o.left, 0);
    line[linelim++] = ',';
    decompile (e->e.o.right->e.o.left, 0);
    line[linelim++] = ',';
    decompile (e->e.o.right->e.o.right, 0);
    line[linelim++] = ')';
}

range_arg(s,e)
char *s;
struct enode *e;
{
    struct range *r;

    for (; line[linelim++] = *s++;);
    linelim--;
    if (r = find_range((char *)0, 0, e->e.r.left.vp,
			     e->e.r.right.vp)) {
	(void)sprintf(line+linelim, "%s", r->r_name);
	linelim += strlen(line+linelim);
    } else {
	decodev (e->e.r.left);
	line[linelim++] = ':';
	decodev (e->e.r.right);
    }
    line[linelim++] = ')';
}

editv (row, col)
int row, col;
{
    register struct ent *p;

    p = lookat (row, col);
    (void)sprintf (line, "let %s = ", v_name(row, col));
    linelim = strlen(line);
    if (p->flags & is_strexpr || p->expr == 0) {
	(void)sprintf (line+linelim, "%.15g", p->v);
	linelim += strlen (line+linelim);
    } else {
        editexp(row,col);
    }
}

editexp(row,col)
int row, col;
{
    register struct ent *p;

    p = lookat (row, col);
    decompile (p->expr, 0);
    line[linelim] = 0;
}

edits (row, col)
int row, col;
{
    register struct ent *p;

    p = lookat (row, col);
    (void)sprintf (line, "%sstring %s = ",
			((p->flags&is_leftflush) ? "left" : "right"),
			v_name(row, col));
    linelim = strlen(line);
    if (p->flags & is_strexpr && p->expr) {
	editexp(row, col);
    } else if (p->label) {
        (void)sprintf (line+linelim, "\"%s\"", p->label);
        linelim += strlen (line+linelim);
    } else {
        (void)sprintf (line+linelim, "\"");
        linelim += 1;
    }
}

Added lex.c.





























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
/*	SC	A Spreadsheet Calculator
 *		Lexical analyser
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *		More mods by Alan Silverstein, 3/88, see list of changes.
 *		$Revision: 1.1 $
 *
 */



#if defined(BSD42) || defined(BSD43)
#include <sys/ioctl.h>
#endif 

#include <curses.h>
#include <signal.h>
#include <setjmp.h>
#include "sc.h"
#include <ctype.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#ifdef VMS
#include "gram_tab.h"
typedef union {
    int ival;
    double fval;
    struct ent *ent;
    struct enode *enode;
    char *sval;
    struct range_s rval;
} YYSTYPE;
extern YYSTYPE yylval;
extern int VMS_read_raw;   /*sigh*/
#else	/* VMS */
#include "y_tab.h"
#endif /* VMS */

char *strtof();

jmp_buf wakeup;
jmp_buf fpe_buf;

struct key {
    char *key;
    int val;
};

struct key experres[] = {
#include "experres.h"
    0, 0};

struct key statres[] = {
#include "statres.h"
    0, 0};

#define ctl(x) ((x) & 037)

yylex ()
{
    register char *p = line+linelim;
    int ret;
    while (isspace(*p)) p++;
    if (*p==0) ret = -1;
    else if (isalpha(*p)) {
	char *tokenst = p;
	register tokenl;
	register struct key *tblp;
	tokenl = 0;
	/*
	 * This picks up either 1 or 2 alpha characters (a column) or
	 * tokens with at least three leading alphas and '_' or digits
	 * (a function or token or command or a range name)
	*/
	while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) {
	    p++;
	    tokenl++;
	}
	if (tokenl <= 2) { /* a COL is 1 or 2 char alpha (and not pi or ln!) */
	    if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') {
		ret = K_PI;
	    } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') {
		ret = K_LN;

	    } else if (tokenl == 2 && tokenst[0] == 'f' && tokenst[1] == 'v') {
		ret = K_FV;
	    } else if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'v') {
		ret = K_PV;

	    } else {
		ret = COL;
		yylval.ival = atocol (tokenst, tokenl);
	    }
	} else {
	    ret = WORD;
	    for (tblp = linelim ? experres : statres; tblp->key; tblp++)
		    if (((tblp->key[0]^tokenst[0])&0137)==0
		     && tblp->key[tokenl]==0) {
			register i = 1;
			while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0)
			    i++;
			if (i>=tokenl) {
			    ret = tblp->val;
			    break;
			}
		    }
	    if (ret==WORD) { 
		struct range *r;
		if (r = find_range(tokenst, tokenl,
				   (struct ent *)0, (struct ent *)0)) {
		    yylval.rval.left = r->r_left;
		    yylval.rval.right = r->r_right;
		    if (r->r_is_range)
		        ret = RANGE;
		    else
			ret = VAR;
		} else {
		    linelim = p-line;
		    yyerror ("Unintelligible word");
		}
	    }
	}
    } else if ((*p == '.') || isdigit(*p)) {
	double v = 0;
	int temp;
	char *nstart = p;
	if (*p != '.') {
	    do v = v*10 + (double)(*p-'0');
	    while (isdigit(*++p));
	}
	if (*p=='.' || *p == 'e' || *p == 'E') {
	    ret = FNUMBER;
	    p = strtof(nstart, &yylval.fval);
	} else {
	    /* A NUMBER must hold at least MAXROW and MAXCOL */
	    /* This is consistent with a short row and col in struct ent */
	    if (v > (double)32767 || v < (double)-32768) {
		ret = FNUMBER;
		yylval.fval = v;
	    } else {
		temp = (int)v;
		if((double)temp != v) {
		    ret = FNUMBER;
		    yylval.fval = v;
		} else {
		    ret = NUMBER;
		    yylval.ival = temp;
		}
	    }
	}
    } else if (*p=='"') {
	char *ptr;
        ptr = p+1;
        while(*ptr && *ptr++ != '"');
        ptr = xmalloc((unsigned)(ptr-p));
	yylval.sval = ptr;
	p += 1;
	while (*p && *p!='"') *ptr++ = *p++;
	*ptr = 0;
	if (*p) p += 1;
	ret = STRING;
    } else if (*p=='[') {
	while (*p && *p!=']') p++;
	if (*p) p++;
	linelim = p-line;
	return yylex();
    } else ret = *p++;
    linelim = p-line;
    return ret;
}


/*
 * Given a token string starting with a symbolic column name and its valid
 * length, convert column name ("A"-"Z" or "AA"-"ZZ") to a column number (0-N).
 * Never mind if the column number is illegal (too high).  The procedure's name
 * and function are the inverse of coltoa().
 * 
 * Case-insensitivity is done crudely, by ignoring the 040 bit.
 */

int
atocol (string, len)
	char	*string;
	int	len;
{
	register int col;

	col = (string [0] & 0137) - 'A';

	if (len == 2)		/* has second char */
	    col = ((col + 1) * 26) + ((string [1] & 0137) - 'A');

	return (col);
}


#ifdef SIMPLE

initkbd()
{}

kbd_again()
{}

resetkbd()
{}

#ifndef VMS

nmgetch()
{
#ifndef INTERNATIONAL
    return (getchar() & 0x7f);
#else
    return (getchar() & 0xff);
#endif /* INTERNATIONAL */
}

#else /* VMS */

nmgetch()
/*
   This is not perfect, it doesn't move the cursor when goraw changes
   over to deraw, but it works well enough since the whole sc package
   is incredibly stable (loop constantly positions cursor).

   Question, why didn't the VMS people just implement cbreak?

   NOTE: During testing it was discovered that the DEBUGGER and curses
   and this method of reading would collide (the screen was not updated
   when continuing from screen mode in the debugger).
*/
{
    short c;
    static int key_id=0;
    int status;
#define VMScheck(a) {if (~(status = (a)) & 1) VMS_MSG (status);}

    if (VMS_read_raw) {
      VMScheck(smg$read_keystroke (&stdkb->_id, &c, 0, 0, 0));
    }
    else
       c = getchar();

    switch (c) {
    case SMG$K_TRM_LEFT:  c = ctl('b'); break;
    case SMG$K_TRM_RIGHT: c = ctl('f'); break;
    case SMG$K_TRM_UP:    c = ctl('p'); break;
    case SMG$K_TRM_DOWN:  c = ctl('n'); break;
    default:   c = c & 0x7f;
    }
    return (c);
}


VMS_MSG (status)
int status;
/*
   Routine to put out the VMS operating system error (if one occurs).
*/
{
#include <descrip.h>
   char errstr[81], buf[120];
   $DESCRIPTOR(errdesc, errstr);
   short int length;
#define err_out(msg) fprintf (stderr,msg)

/* Check for no error or standard error */

   if (~status & 1) {
      status = status & 0x8000 ? status & 0xFFFFFFF : status & 0xFFFF;
      if (SYS$GETMSG(status, &length, &errdesc, 1, 0) == SS$_NORMAL) {
         errstr[length] = '\0';
         sprintf (buf, "<0x%x> %s", status, errdesc.dsc$a_pointer);
         err_out (buf);
      }
      else
         err_out ("System error");
   }
}
#endif /* VMS */

#else /*SIMPLE*/

#if defined(BSD42) || defined (SYSIII) || defined(BSD43)

#define N_KEY 4

struct key_map {
    char *k_str;
    char k_val;
    char k_index;
}; 

struct key_map km[N_KEY];

char keyarea[N_KEY*10];

char *tgetstr();
char *getenv();
char *ks;
char ks_buf[20];
char *ke;
char ke_buf[20];

#ifdef TIOCSLTC
struct ltchars old_chars, new_chars;
#endif

char dont_use[] = {
    ctl('z'), ctl('r'), ctl('l'), ctl('b'),
    ctl('c'), ctl('f'), ctl('g'), ctl('['),
    ctl('h'), ctl('m'), ctl('j'), ctl('n'),
    ctl('p'), ctl('q'), ctl('s'), ctl('t'),
    ctl('u'), ctl('v'), ctl('e'), ctl('a'),
    ctl('i'), ctl('w'), 0,
};

charout(c)
int c;
{
	(void)putchar(c);
}

initkbd()
{
    register struct key_map *kp;
    register i,j;
    char *p = keyarea;
    char *ktmp;
    static char buf[1024]; /* Why do I have to do this again? */

    if (tgetent(buf, getenv("TERM")) <= 0)
	return;

    km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl('b');
    km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl('f');
    km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl('p');
    km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl('n');
    ktmp = tgetstr("ks",&p);
    if (ktmp)  {
	(void) strcpy(ks_buf, ktmp);
	ks = ks_buf;
	tputs(ks, 1, charout);
    }
    ktmp = tgetstr("ke",&p);
    if (ktmp)  {
	(void) strcpy(ke_buf, ktmp);
	ke = ke_buf;
    }

    /* Unmap arrow keys which conflict with our ctl keys   */
    /* Ignore unset, longer than length 1, and 1-1 mapped keys */

    for (i = 0; i < N_KEY; i++) {
	kp = &km[i];
	if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
	    for (j = 0; dont_use[j] != 0; j++)
	        if (kp->k_str[0] == dont_use[j]) {
		     kp->k_str = (char *)0;
		     break;
		}
    }


#ifdef TIOCSLTC
    (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
    new_chars = old_chars;
    if (old_chars.t_lnextc == ctl('v'))
	new_chars.t_lnextc = -1;
    if (old_chars.t_rprntc == ctl('r'))
	new_chars.t_rprntc = -1;
    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
#endif
}

kbd_again()
{
    if (ks) 
	tputs(ks, 1, charout);

#ifdef TIOCSLTC
    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
#endif
}

resetkbd()
{
    if (ke) 
	tputs(ke, 1, charout);

#ifdef TIOCSLTC
    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
#endif
}

nmgetch() 
{
    register int c;
    register struct key_map *kp;
    register struct key_map *biggest;
    register int i;
    int almost;
    int maybe;

    static char dumpbuf[10];
    static char *dumpindex;

#ifdef SIGVOID
    void time_out();
#else
    int time_out();
#endif

    if (dumpindex && *dumpindex)
	    return (*dumpindex++);

#ifndef INTERNATIONAL
    c = getchar() & 0x7f;
#else
    c = getchar() & 0xff;
#endif /* INTERNATIONAL */
    biggest = 0;
    almost = 0;

    for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
	if (!kp->k_str)
	    continue;
	if (c == kp->k_str[kp->k_index]) {
	    almost = 1;
	    kp->k_index++;
	    if (kp->k_str[kp->k_index] == 0) {
		c = kp->k_val;
	        for (kp = &km[0]; kp < &km[N_KEY]; kp++)
	            kp->k_index = 0;
	        return(c);
	    }
	}
	if (!biggest && kp->k_index)
	    biggest = kp;
        else if (kp->k_index && biggest->k_index < kp->k_index)
	    biggest = kp;
    }

    if (almost) { 

        (void) signal(SIGALRM, time_out);
        (void) alarm(1);

	if (setjmp(wakeup) == 0) { 
	    maybe = nmgetch();
	    (void) alarm(0);
	    return(maybe);
	}
    }
    
    if (biggest) {
	for (i = 0; i<biggest->k_index; i++) 
	    dumpbuf[i] = biggest->k_str[i];
	dumpbuf[i++] = c;
	dumpbuf[i] = 0;
	dumpindex = &dumpbuf[1];
	for (kp = &km[0]; kp < &km[N_KEY]; kp++)
	    kp->k_index = 0;
	return (dumpbuf[0]);
    }

    return(c);
}

#endif

#if defined(SYSV2) || defined(SYSV3)

initkbd()
{
    keypad(stdscr, TRUE);
}

kbd_again()
{
    keypad(stdscr, TRUE);
}

resetkbd()
{
    keypad(stdscr, FALSE);
}

nmgetch()
{
    register int c;

    c = getch();
    switch (c) {
    case KEY_LEFT:  c = ctl('b'); break;
    case KEY_RIGHT: c = ctl('f'); break;
    case KEY_UP:    c = ctl('p'); break;
    case KEY_DOWN:  c = ctl('n'); break;
#ifdef KEY_C1
/* This stuff works for a wyse wy75 in ANSI mode under 5.3.  Good luck. */
/* It is supposed to map the curses keypad back to the numeric equiv. */
    case KEY_C1:    c = '0'; break;
    case KEY_A1:    c = '1'; break;
    case KEY_B2:    c = '2'; break;
    case KEY_A3:    c = '3'; break;
    case KEY_F(5):  c = '4'; break;
    case KEY_F(6):  c = '5'; break;
    case KEY_F(7):  c = '6'; break;
    case KEY_F(9):  c = '7'; break;
    case KEY_F(10): c = '8'; break;
    case KEY_F0:    c = '9'; break;
    case KEY_C3:    c = '.'; break;
    case KEY_ENTER: c = ctl('m'); break;
#endif
#ifndef INTERNATIONAL
    default:   c = c & 0x7f; 
#else
    default:   c = c & 0xff; 
#endif /* INTERNATIONAL */
    break;
    }
    return (c);
}

#endif /* SYSV2 || SYSV3 */

#endif /* SIMPLE */

#ifdef SIGVOID
void
#endif
time_out()
{
    longjmp(wakeup, -1);
}

#ifdef SIGVOID
void
#endif
fpe_trap()
{
    longjmp(fpe_buf, 1);
}

/*
 * This converts a floating point number of the form
 * [s]ddd[.d*][esd*]  where s can be a + or - and e is E or e.
 * to floating point. 
 * p is advanced.
 */

char *
strtof(p, res)
register char *p;
double *res;
{
    double acc;
    int sign;
    double fpos;
    int exp;
    int exps;
#ifdef SIGVOID
    void (*sig_save)();
#else
    int (*sig_save)();
#endif

    sig_save = signal(SIGFPE, fpe_trap);
    if (setjmp(fpe_buf)) {
	error("Floating point exception\n");
	*res = 0.0; 
        (void) signal(SIGFPE, sig_save);
	return(p);
    }
    acc = 0.0;
    sign = 1;
    exp = 0;
    exps = 1;
    if (*p == '+')
        p++;
    else if (*p == '-') {
        p++;
        sign = -1;
    }
    while (isdigit(*p)) {
        acc = acc * 10.0 + (double)(*p - '0');
        p++;
    }
    if (*p == 'e' || *p == 'E') {
	    p++;
        if (*p == '+')
	    p++;
        else if (*p == '-') {
	    p++;
	    exps = -1;
        }
        while(isdigit(*p)) {
	    exp = exp * 10 + (*p - '0');
	    p++;
        }
    }
    if (*p == '.') {
	fpos = 1.0/10.0;
	p++;
	while(isdigit(*p)) {
	    acc += (*p - '0') * fpos;
	    fpos *= 1.0/10.0;
	    p++;
	}
    }
    if (*p == 'e' || *p == 'E') {
	exp = 0;
	exps = 1;
        p++;
	if (*p == '+')
	    p++;
	else if (*p == '-') {
	    p++;
	    exps = -1;
	}
	while(isdigit(*p)) {
	    exp = exp * 10 + (*p - '0');
	    p++;
	}
    }
    if (exp) {
	if (exps > 0)
	    while (exp--)
		acc *= 10.0;
	else
	    while (exp--)
		acc *= 1.0/10.0;
    }
    if (sign > 0)
        *res = acc;
    else
	*res = -acc;

    (void) signal(SIGFPE, sig_save);
    return(p);
}

Added psc.c.

































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/* Sc parse routine
 *
 * usage psc options
 * options:
 *   -L		Left justify strings.  Default is right justify.
 *   -r		Assemble data into rows first, not columns.
 *   -R	n	Increment by n between rows 
 *   -C n	Increment by n between columns
 *   -n n	Length of the row (column) should be n.
 *   -s v	Top left location in the spreadsheet should be v; eg, k5
 *   -d c       Use c as the delimiter between the fields.
 *   -k         Keep all delimiters - Default is strip multiple delimiters to 1.
 *   
 *  Author: Robert Bond
 *		$Revision: 1.1 $
 */

#include <ctype.h>
#include <stdio.h>
#include "sc.h"

#define END 0
#define NUM 1
#define ALPHA 2
#define SPACE 3
#define EOL 4

extern char *optarg;
extern int   optind;
char *coltoa();
char *progname;

#ifdef SYSV3
extern void exit();
#else
extern int exit();
#endif

int colfirst = 0;
int r0 = 0;
int c0 = 0;
int rinc = 1;
int cinc = 1;
int leftadj = 0;
int len = 20000;
char delim1 = ' ';
char delim2 = '\t';
int strip_delim = 1;
int fwidth[MAXCOLS];
int precision[MAXCOLS];

char token[1000];

main(argc, argv)
int argc;
char **argv;
{
    int curlen;
    int curcol, coff;
    int currow, roff;
    int first;
    int c;
    register effr, effc;
    int i,j;
    register char *p;

    progname = argv[0];
    while ((c = getopt(argc, argv, "rLks:R:C:n:d:")) != EOF) {
	switch(c) {
	case 'r':
	    colfirst = 1;
	    break;
	case 'L':
	    leftadj = 1;
	    break;
	case 's':
	    c0 = getcol(optarg);
	    r0 = getrow(optarg);
	    break;
	case 'R':
	    rinc = atoi(optarg);
	    break;
	case 'C':
	    cinc = atoi(optarg);
	    break;
	case 'n':
	    len = atoi(optarg);
	    break;
	case 'd':
	    delim1 = optarg[0];
	    delim2 = 0;
	    break;
	case 'k':
	    strip_delim = 0;
	    break;
	default:
	    (void) fprintf(stderr,"Usage: %s [-rkL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
	    exit(1);
        }
    }

    if (optind < argc) {
	    (void) fprintf(stderr,"Usage: %s [-rL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
	    exit(1);
    }

    curlen = 0;
    curcol = c0; coff = 0;
    currow = r0; roff = 0;
    first = 1;

    while(1) {

	effr = currow+roff;
	effc = curcol+coff;

	switch(scan()) {
	case END:
	    for (i = 0; i<MAXCOLS; i++) {
		if (precision[i])
		    (void) printf("format %s %d %d\n", coltoa(i), precision[i]+1,
			fwidth[i]);
	    }
	    exit(0);
	case NUM:
	    first = 0;
	    (void) printf("let %s%d = %s\n", coltoa(effc), effr, token);
	    if (effc > MAXCOLS-1)
		(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
	    else {
		i = 0;
		j = 0;
		p = token;
		while (*p && *p != '.') {
		    p++; i++;
		}
		if (*p) {
		    p++; i++;
		}
		while (*p) {
		    p++; i++; j++;
		}
		if (precision[effc] < i)
		    precision[effc] = i;
		if (fwidth[effc] < j)
		    fwidth[effc] = j;
	    }
	    break;
	case ALPHA:
	    first = 0;
	    if (leftadj)
		(void) printf("leftstring %s%d = \"%s\"\n", coltoa(effc),effr,token); 
	    else
		(void) printf("rightstring %s%d = \"%s\"\n",coltoa(effc),effr,token); 
	    if (effc > MAXCOLS-1)
		(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
	    else {
		i = strlen(token);
		if (i > precision[effc])
		    precision[effc] = i;
	    }
	    break;
	case SPACE:
	    if (first && strip_delim)
		break;
	    if (colfirst)
		roff++;
	    else
		coff++;
	    break;
	case EOL:
	    curlen++;
	    roff = 0;
	    coff = 0;
	    first = 1;
	    if (colfirst) {
		if (curlen >= len) {
		    curcol = c0;
		    currow += rinc;
		    curlen = 0;
		} else {
		    curcol += cinc;
		}
	    } else {
		if (curlen >= len) {
		    currow = r0;
		    curcol += cinc;
		    curlen = 0;
		} else {
		    currow += rinc;
		}
	    }
	    break;
	}
    }
}

scan()
{
    register int c;
    register char *p;

    p = token;
    c = getchar();

    if (c == EOF)
	return(END);

    if (c == '\n')
	return(EOL);

    if (c == delim1 || c == delim2) {
        if (strip_delim) {
	    while ((c = getchar()) && (c == delim1 || c == delim2))
	        ;
	    (void)ungetc(c, stdin);
	} 
	return(SPACE);
    }

    if (c == '\"') {
	while ((c = getchar()) && c != '\"' && c != '\n' && c != EOF)
	    *p++ = c;
	if (c != '\"')
	    (void)ungetc(c, stdin);
	*p = 0;
	return(ALPHA);
    }

    while (c != delim1 && c != delim2 && c!= '\n' && c != EOF) {
	*p++ = c;
	c = getchar();
    }
    *p = 0;
    (void)ungetc(c, stdin);

    p = token;
    c = *p;
    if (isdigit(c) || c == '.' || c == '-' || c == '+') {
	while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e'
	    || c == 'E') {
		c = *p++;
	}
	if (c == 0)
	    return(NUM);
	else
	    return(ALPHA);
    }

    return(ALPHA);
}
    
getcol(p)
char *p;
{
    register  col;

    if (!p)
	return(0);
    while(*p && !isalpha(*p)) 
	p++; 
    if (!*p)
	return(0);
    col = ((*p & 0137) - 'A');
    if (isalpha(*++p)) 
	col = (col + 1)*26 + ((*p & 0137) - 'A');
    return(col);
}

getrow(p)
char *p;
{
    int row;

    if (!p)
	return(0);
    while(*p && !isdigit(*p))
	p++; 
    if (!*p)
	return(0);
    if (sscanf(p, "%d", &row) != 1)
	return(0);
    return(row);
}

char *
coltoa(col)
int col;
{
    static char rname[3];
    register char *p = rname;

    if (col < 0 || col > 25*26) 
	(void) fprintf(stderr,"coltoa: invalid col: %d", col);

    if (col > 25) {
	*p++ = col/26 + 'A' - 1;
	col %= 26;
    }
    *p++ = col+'A';
    *p = 0;
    return(rname);
}

Added range.c.













































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

/*	SC	A Spreadsheet Calculator
 *		Range Manipulations
 *
 *              Robert Bond, 4/87
 *
 *		$Revision: 1.1 $
 */

#include <stdio.h>
#include <curses.h>
#include <ctype.h>
#include "sc.h"

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

static struct range *rng_base;

add_range(name, left, right, is_range)
char *name;
struct ent_ptr left, right;
int is_range;
{
    struct range *r;
    register char *p;
    int len;
    int minr,minc,maxr,maxc;
    int minrf, mincf, maxrf, maxcf;

    if (left.vp->row < right.vp->row) {
	minr = left.vp->row; minrf = left.vf & FIX_ROW;
	maxr = right.vp->row; maxrf = right.vf & FIX_ROW;
    } else {
	minr = right.vp->row; minrf = right.vf & FIX_ROW;
	maxr = left.vp->row; maxrf = right.vf & FIX_ROW;
    } 

    if (left.vp->col < right.vp->col) {
	minc = left.vp->col; mincf = left.vf & FIX_COL;
	maxc = right.vp->col; maxcf = right.vf & FIX_COL;
    } else {
	minc = right.vp->col; mincf = right.vf & FIX_COL;
	maxc = left.vp->col; maxcf = left.vf & FIX_COL;
    } 

    left.vp = lookat(minr, minc);
    left.vf = minrf | mincf;
    right.vp = lookat(maxr, maxc);
    right.vf = maxrf | maxcf;

    if (find_range(name, strlen(name), (struct ent *)0, (struct ent *)0)) {
	error("Error: range name already defined");
	xfree(name);
	return;
    }

    if (strlen(name) <= 2) {
	error("Invalid range name - too short");
	xfree(name);
	return;
    }

    for(p=name, len=0; *p; p++, len++)
	if (!((isalpha(*p) && (len<=2)) ||
	    ((isdigit(*p) || isalpha(*p) || (*p == '_')) && (len>2)))) {
	    error("Invalid range name - illegal combination");
	    xfree(name);
	    return;
        }

    r = (struct range *)xmalloc((unsigned)sizeof(struct range));
    r->r_name = name;
    r->r_left = left;
    r->r_right = right;
    r->r_next = rng_base;
    r->r_prev = 0;
    r->r_is_range = is_range;
    if (rng_base)
        rng_base->r_prev = r;
    rng_base = r;
}

del_range(left, right)
struct ent *left, *right;
{
    register struct range *r;
    int minr,minc,maxr,maxc;

    minr = left->row < right->row ? left->row : right->row;
    minc = left->col < right->col ? left->col : right->col;
    maxr = left->row > right->row ? left->row : right->row;
    maxc = left->col > right->col ? left->col : right->col;

    left = lookat(minr, minc);
    right = lookat(maxr, maxc);

    if (!(r = find_range((char *)0, 0, left, right))) 
	return;

    if (r->r_next)
        r->r_next->r_prev = r->r_prev;
    if (r->r_prev)
        r->r_prev->r_next = r->r_next;
    else
	rng_base = r->r_next;
    xfree((char *)(r->r_name));
    xfree((char *)r);
}

clean_range()
{
    register struct range *r;
    register struct range *nextr;

    r = rng_base;
    rng_base = 0;

    while (r) {
	nextr = r->r_next;
	xfree((char *)(r->r_name));
	xfree((char *)r);
	r = nextr;
    }
}

/* Match on name or lmatch, rmatch */

struct range *
find_range(name, len, lmatch, rmatch)
char *name;
int len;
struct ent *lmatch;
struct ent *rmatch;
{
    struct range *r;
    register char *rp, *np;
    register int c;

    if (name) {
	for (r = rng_base; r; r = r->r_next) {
	    for (np = name, rp = r->r_name, c = len;
		 c && *rp && (*rp == *np);
		 rp++, np++, c--) /* */;
	    if (!c && !*rp)
		return(r);
	}
	return(0);
    }

    for (r = rng_base; r; r= r->r_next) {
	if ((lmatch == r->r_left.vp) && (rmatch == r->r_right.vp)) 
	    return(r);
    }
    return(0);
}

sync_ranges()
{
    register struct range *r;

    r = rng_base;
    while(r) {
	r->r_left.vp = lookat(r->r_left.vp->row, r->r_left.vp->col);
	r->r_right.vp = lookat(r->r_right.vp->row, r->r_right.vp->col);
	r = r->r_next;
    }
}

write_range(f)
FILE *f;
{
    register struct range *r;

    for (r = rng_base; r; r = r->r_next) {
	(void) fprintf(f, "define \"%s\" %s%s%s%d",
			r->r_name,
			r->r_left.vf & FIX_COL ? "$":"",
			coltoa(r->r_left.vp->col), 
			r->r_left.vf & FIX_ROW ? "$":"",
			r->r_left.vp->row);
	if (r->r_is_range)
	    (void) fprintf(f, ":%s%s%s%d\n",
			    r->r_right.vf & FIX_COL ? "$":"",
			    coltoa(r->r_right.vp->col), 
			    r->r_right.vf & FIX_ROW ? "$":"",
			    r->r_right.vp->row);
	else
	    (void) fprintf(f, "\n");
    }
}

list_range(f)
FILE *f;
{
    register struct range *r;

    (void) fprintf(f, "%-30s %s\n\n","Name","Definition");

    for (r = rng_base; r; r = r->r_next) {
	(void) fprintf(f, "%-30s %s%s%s%d",
			    r->r_name,
			    r->r_left.vf & FIX_COL ? "$":"",
			    coltoa(r->r_left.vp->col), 
			    r->r_left.vf & FIX_ROW ? "$":"",
			    r->r_left.vp->row);
	if (r->r_is_range)
	    (void) fprintf(f, ":%s%s%s%d\n",
			    r->r_right.vf & FIX_COL ? "$":"",
			    coltoa(r->r_right.vp->col), 
			    r->r_right.vf & FIX_ROW ? "$":"",
			    r->r_right.vp->row);
	else
	    (void) fprintf(f, "\n");
    }
}

char *
v_name(row, col)
int row, col;
{
    struct ent *v;
    struct range *r;
    static char buf[20];

    v = lookat(row, col);
    if (r = find_range((char *)0, 0, v, v)) {
	return(r->r_name);
    } else {
        (void) sprintf(buf, "%s%d", coltoa(col), row);
	return(buf);
    }
}

char *
r_name(r1, c1, r2, c2)
int r1, c1, r2, c2;
{
    struct ent *v1, *v2;
    struct range *r;
    static char buf[100];

    v1 = lookat(r1, c1);
    v2 = lookat(r2, c2);
    if (r = find_range((char *)0, 0, v1, v2)) {
	return(r->r_name);
    } else {
        (void) sprintf(buf, "%s", v_name(r1, c1));
	(void) sprintf(buf+strlen(buf), ":%s", v_name(r2, c2));
	return(buf);
    }
}

are_ranges()
{
return (rng_base != 0);
}

Added sc.c.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
/*	SC	A Spreadsheet Calculator
 *		Main driver
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *		More mods by Alan Silverstein, 3-4/88, see list of changes.
 *
 * 		mods cire 9/90
 * 		    - added more emacs control chars for screen movement.
 */


#include <signal.h>
#include <curses.h>
#include <stdlib.h>
#include <stdio.h>
#include "sc.h"

/*
 * CODE REVISION NUMBER:
 *
 * The part after the first colon, except the last char, appears on the screen.
 * The '$' is converted to a space.
 */

char *realrev = "$Revision: 1.1 $ala cire - base 6.1";
static char *rev;

#ifndef DFLT_PAGER
#define	DFLT_PAGER "less"	/* more is probably more widespread than less */
#endif /* DFLT_PAGER */

#define MAXCMD 160	/* for ! command below */

/* Globals defined in sc.h */

struct ent *tbl[MAXROWS][MAXCOLS];
int strow, stcol;
int currow, curcol;
int savedrow, savedcol;
int FullUpdate;
int maxrow, maxcol;
int fwidth[MAXCOLS];
int precision[MAXCOLS];
char col_hidden[MAXCOLS];
char row_hidden[MAXROWS];
char line[1000];
int changed;
struct ent *to_fix;
int modflg;
int numeric;
char *mdir;
int showsc, showsr;	/* Starting cell for highlighted range */

char curfile[1024];
char    revmsg[80];

int  linelim = -1;

int  showtop   = 1;	/* Causes current cell value display in top line  */
int  showcell  = 1;	/* Causes current cell to be highlighted	  */
int  showrange = 0;	/* Causes ranges to be highlighted		  */
int  showneed  = 0;	/* Causes cells needing values to be highlighted  */
int  showexpr  = 0;	/* Causes cell exprs to be displayed, highlighted */

int  autocalc = 1 ;	/* 1 to calculate after each update */
int  calc_order = BYROWS;
int  tbl_style = 0;	/* headers for T command output */

int  lastmx, lastmy;	/* Screen address of the cursor */
int  lastcol;		/* Spreadsheet Column the cursor was in last */
char under_cursor[2];	/* Data under the < cursor */

#ifdef VMS
int VMS_read_raw = 0;
#endif

int seenerr;

static void repaint(int x, int y, int len);
static void signals(void);

void
yyerror (err)
char *err; {
    if (seenerr) return;
    seenerr++;
    (void) move (1,0);
    (void) clrtoeol ();
    (void) printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
}

struct ent *
lookat(int row, int col){
    register struct ent **p;
    if (row < 0)
	row = 0;
    else if (row > MAXROWS-1) 
	row = MAXROWS-1;
    if (col < 0) 
	col = 0;
    else if (col > MAXCOLS-1)
	col = MAXCOLS-1;
    p = &tbl[row][col];
    if (*p==0) {
	*p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent));
	if (row>maxrow) maxrow = row;
	if (col>maxcol) maxcol = col;
	(*p)->label = 0;
	(*p)->flags = 0;
	(*p)->row = row;
	(*p)->col = col;
	(*p)->expr = 0;
	(*p)->v = (double) 0.0;
    }
    return *p;
}

/*
 * This structure is used to keep ent structs around before they
 * are deleted to allow the sync_refs routine a chance to fix the
 * variable references.
 * We also use it as a last-deleted buffer for the 'p' command.
 */

void
free_ent(p)
register struct ent *p;
{
    p->next = to_fix;
    to_fix = p;
    p->flags |= is_deleted;
}

void
flush_saved()
{
    register struct ent *p;
    register struct ent *q;

    if (!(p = to_fix))
	return;
    while (p) {
	(void) clearent(p);
	q = p->next;
	xfree((char *)p);
	p = q;
    }
    to_fix = 0;
}

void
update ()
{
    int row, col, r, i;
    struct ent **p;
    int     mxcol;
    int     mxrow;
    int     rows;
    int     cols;
    int     minsr, minsc, maxsr, maxsc;

    while (row_hidden[currow])   /* You can't hide the last row or col */
	currow++;
    while (col_hidden[curcol])
	curcol++;
    /* First see if the last display still covers curcol */
    if (stcol <= curcol) { 
	for (i = stcol, cols = 0, col = RESCOL;
			(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (col_hidden[i])
		continue;
	    col += fwidth[i];
	}
    }
    while (stcol + cols - 1 < curcol || curcol < stcol) {
	FullUpdate++;
	if (stcol - 1 == curcol) {    /* How about back one? */
	    stcol--;
	} else if (stcol + cols == curcol) {   /* Forward one? */
	    stcol++;
	} else {
	    /* Try to put the cursor in the center of the screen */
	    col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
	    stcol = curcol;
	    for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
		stcol--;
		if (col_hidden[i])
		    continue;
		col -= fwidth[i];
	    }
	}
	/* Now pick up the counts again */
	for (i = stcol, cols = 0, col = RESCOL;
			(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (col_hidden[i])
		continue;
	    col += fwidth[i];
	}
    }
    /* Now - same process on the rows */
    if (strow <= currow) { 
	for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
	    rows++;
	    if (row_hidden[i])
		continue;
	    row++;
	}
    }
    while (strow + rows - 1 < currow || currow < strow) {
	FullUpdate++;
	if (strow - 1 == currow) {    /* How about up one? */
	    strow--;
	} else if (strow + rows == currow) {   /* Down one? */
	    strow++;
	} else {
	    /* Try to put the cursor in the center of the screen */
	    row = (LINES - RESROW) / 2 + RESROW; 
	    strow = currow;
	    for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
		strow--;
		if (row_hidden[i])
		    continue;
		row--;
	    }
	}
	/* Now pick up the counts again */
	for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
	    rows++;
	    if (row_hidden[i])
		continue;
	    row++;
	}
    }
    mxcol = stcol + cols - 1;
    mxrow = strow + rows - 1;
    if (FullUpdate) {
	(void) move (2, 0);
	(void) clrtobot ();
	(void) standout();
	for (row=RESROW, i=strow; i <= mxrow; i++) {
	    if (row_hidden[i]) 
		continue;
	    (void) move(row,0);
#if MAXROW < 1000
	    (void) printw("%-*d", RESCOL-1, i);
#else
	    (void) printw("%-*d", RESCOL, i);
#endif
	    row++;
	}
	(void) move (2,0);
	(void) printw("%*s", RESCOL, " ");
	for (col=RESCOL, i = stcol; i <= mxcol; i++) {
	    register int k;
	    if (col_hidden[i])
		continue;
	    (void) move(2, col);
	    k = fwidth[i]/2;
	    if (k == 0)
		(void) printw("%1s", coltoa(i));
	    else
	        (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
	    col += fwidth[i];
	}
	(void) standend();
    }

    /* Get rid of cursor standout on the cell at previous cursor position */
    (void) move(lastmx, lastmy);
    if (showcell)
        repaint(lastmx, lastmy, fwidth[lastcol]);

    if (showrange) {
	minsr = showsr < currow ? showsr : currow;
	minsc = showsc < curcol ? showsc : curcol;
	maxsr = showsr > currow ? showsr : currow;
	maxsc = showsc > curcol ? showsc : curcol;

	if (showtop) {
	    (void) move(1,0);
	    (void) clrtoeol();
	    (void) printw("Default range:  %s",
			    r_name(minsr, minsc, maxsr, maxsc));
	}
    }

    /* Repaint the visible screen */
    for (row = strow, r = RESROW; row <= mxrow; row++) {
	register c = RESCOL;
	int do_stand = 0;
	int fieldlen;
	int nextcol;

	if (row_hidden[row])
	    continue;
	for (p = &tbl[row][col = stcol]; col <= mxcol;
	         p += nextcol - col,  col = nextcol, c += fieldlen) {

	    nextcol = col+1;
	    if (col_hidden[col]) {
		fieldlen = 0;
		continue;
	    }

	    fieldlen = fwidth[col];

	    /*
	     * Set standout if:
	     *
	     * - showing ranges, and not showing cells which need to be filled
	     *   in, and not showing cell expressions, and in a range, OR
	     *
	     * - if showing cells which need to be filled in and this one is
	     *   of that type (has a value and doesn't have an expression, or
	     *   it is a string expression), OR
	     *
	     * - if showing cells which have expressions and this one does.
	     */

	    if ((showrange && (! showneed) && (! showexpr)
			   && (row >= minsr) && (row <= maxsr)
			   && (col >= minsc) && (col <= maxsc))

	     || (showneed && (*p) && ((*p) -> flags & is_valid)
	      && (((*p) -> flags & is_strexpr) || ! ((*p) -> expr)))

	     || (showexpr && (*p) && ((*p) -> expr)))
	    {
		do_stand = 1;
	    }

	    if (*p && ((*p) -> flags & is_changed || FullUpdate) || do_stand) {
		(void) move (r, c);
		if (!*p)
		    *p = lookat(row, col);
		if (do_stand) {
		    (void) standout();
		    (*p) -> flags |= is_changed; 
		} else {
		    (*p) -> flags &= ~is_changed;
		}

		/*
		 * Show expression; takes priority over other displays:
		 */

		if (showexpr && ((*p) -> expr)) {
		    linelim = 0;
		    editexp (row, col);		/* set line to expr */
		    linelim = -1;
		    showstring (line, /* leftflush = */ 1, /* hasvalue = */ 0,
				row, col, & nextcol, mxcol, & fieldlen, r, c);
		}
		else {

		    /*
		     * Show cell's numeric value:
		     */

		    if ((*p) -> flags & is_valid) {
			char field[1024];
			(void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*p)->v);
			if(strlen(field) > fwidth[col]) {
			    for(i = 0; i<fwidth[col]; i++)
				(void)addch('*');
			} else {
			    (void)addstr(field);
			}
		    }

		    /*
		     * Show cell's label string:
		     */

		    if ((*p) -> label) {
			showstring ((*p) -> label,
				    (*p) -> flags & is_leftflush,
				    (*p) -> flags & is_valid,
				    row, col, & nextcol, mxcol,
				    & fieldlen, r, c);
		    }

		    /*
		     * repaint a blank cell:
		     */

		    if (!((*p)->flags & is_valid) && !(*p)->label) {
			(void) printw ("%*s", fwidth[col], " ");
		    }
		} /* else */

		if (do_stand) {
		    (void) standend();
		    do_stand = 0;
		}
	    }
	}
	r++;
    }
	    
    (void) move(lastmy, lastmx+fwidth[lastcol]);
#ifndef INTERNATIONAL
    if((inch() & 0x7f) == '<')
#else
    if((inch() & 0xff) == '<')
#endif /* INTERNATIONAL */
        (void) addstr(under_cursor);
    lastmy =  RESROW;
    for (row = strow; row < currow; row++)
	if (!row_hidden[row])
		lastmy += 1;
    lastmx = RESCOL;
    for (col = stcol; col < curcol; col++)
	if (!col_hidden[col])
		lastmx += fwidth[col];
    lastcol = curcol;
    (void) move(lastmx, lastmy);
    if (showcell && (! showneed) && (! showexpr)) {
        (void) standout();
        repaint(lastmx, lastmy, fwidth[lastcol]);
        (void) standend();
    }
    (void) move(lastmy, lastmx+fwidth[lastcol]);
#ifndef INTERNATIONAL /*changed to make consistent with all other uses of INTERNATIONAL */
    *under_cursor = (inch() & 0x7f);
#else
    *under_cursor = (inch() & 0xff);
#endif /* INTERNATIONAL */
    (void) addstr("<");

    (void) move (0, 0);
    (void) clrtoeol ();
    if (linelim >= 0) {
	(void) addstr (">> ");
	(void) addstr (line);
    } else {
	if (showtop) {			/* show top line */
	    register struct ent *p1;
	    int printed = 0;		/* printed something? */

            (void) printw ("%s%d ", coltoa (curcol), currow);

	    if (p1 = tbl [currow] [curcol])
	    {
		if (p1 -> expr)		/* has expr of some type */
		{
		    linelim = 0;
		    editexp (currow, curcol);	/* set line to expr */
		    linelim = -1;
		}

		/*
		 * Display string part of cell:
		 */

		if ((p1 -> expr) && (p1 -> flags & is_strexpr))
		{
		    (void) addstr ((p1 -> flags & is_leftflush) ? "<{" : ">{");
		    (void) addstr (line);
		    (void) addstr ("} ");	/* and this '}' is for vi % */
		    printed = 1;
		}
		else if (p1 -> label)		/* has constant label only */
		{
		    (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\"");
		    (void) addstr (p1 -> label);
		    (void) addstr ("\" ");
		    printed = 1;
		}

		/*
		 * Display value part of cell:
		 */

		if (p1 -> flags & is_valid)	/* has value or num expr */
		{
		    if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr))
			(void) sprintf (line, "%.15g", p1 -> v);

		    (void) addstr ("[");
		    (void) addstr (line);
		    (void) addstr ("]");
		    printed = 1;
		}
	    }

	    if (! printed)
		(void) addstr ("[]");
	}
	(void) move (lastmy, lastmx + fwidth[lastcol]);
    }
    if (revmsg[0]) {
	(void) move(0, 0);
	(void) clrtoeol ();	/* get rid of topline display */
	(void) printw(revmsg);
	revmsg[0] = 0;		/* don't show it again */
	(void) move (lastmy, lastmx + fwidth[lastcol]);
    }
    FullUpdate = 0;
}

void
repaint(x, y, len)
int x, y, len;
{
    char buf[4];

    strcpy(buf, " ");

    while(len-- > 0) {
	(void) move(y,x);
#ifndef INTERNATIONAL
	*buf = inch() & 0x7f;
#else
	*buf = inch() & 0xff;
#endif /* INTERNATIONAL */
	(void) addstr(buf);
	x++;
    }
}

char    *progname;

int
main (int argc, char **argv)
{
    int     inloop = 1;
    register int   c;
    int     edistate = -1;
    int     arg = 1;
    int     narg;
    int     nedistate;
    int	    running;
    char    *revi;

    /*
     * Keep command line options around until the file is read so the
     * command line overrides file options
     */

    int Mopt = 0;
    int Nopt = 0;
    int Copt = 0; 
    int Ropt = 0;

    progname = argv[0];
    while (argc > 1 && argv[1][0] == '-') {
	argv++;
	argc--;
    	switch (argv[0][1]) {
	    case 'x':
#ifdef VMS
		    (void) fprintf(stderr, "Crypt not available for VMS\n");
		    exit(1);
#else 
		    Crypt = 1;
#endif
		    break;
	    case 'm':
		    Mopt = 1;
		    break;
	    case 'n':
		    Nopt = 1;
		    break;
	    case 'c':
		    Copt = 1;
		    break;
	    case 'r':
		    Ropt = 1;
		    break;
	    default:
		    (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n",
			progname,argv[0][1]);
		    exit(1);
	}
    }

    {
	int i;
	for (i = 0; i < MAXCOLS; i++) {
	    fwidth[i] = DEFWIDTH;
	    precision[i] = DEFPREC;
	}
    }
    curfile[0]=0;
    strcpy(under_cursor, " ");

    signals();
    (void) initscr();
    (void) clear();
#ifdef VMS
    VMS_read_raw = 1;
#else
    nonl();
    noecho ();
    cbreak();
#endif
    initkbd();


    /*
     * Build revision message for later use:
     */
    rev = strdup(realrev);
    (void) strcpy (revmsg, progname);
    for (revi = rev; (*revi++) != ':'; ); /* start after 1st colon */
    for (; (*revi++) != '$'; );
    *--revi = ' ';
    for (revi = rev; (*revi++) != ':'; );	/* copy after colon */
    (void) strcat (revmsg, revi);
    (void) strcat (revmsg, ":  Type '?' for help.");

    if (argc > 1) {
	(void) strcpy(curfile,argv[1]);
	readfile (argv[1], 0);
    }

    if (Mopt)
	autocalc = 0;
    if (Nopt)
	numeric = 1;
    if (Copt)
	calc_order = BYCOLS;
    if (Ropt)
	calc_order = BYROWS;

    modflg = 0;
#ifdef VENIX
    setbuf (stdin, NULL);
#endif
    FullUpdate++;
    while (inloop) { running = 1;
    while (running) {
	nedistate = -1;
	narg = 1;
	if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate))
	    EvalAll (), changed = 0;
	update();
#ifndef SYSV3
	(void) refresh(); /* 5.3 does a refresh in getch */ 
#endif
	c = nmgetch();
	(void) move (1, 0);
	(void) clrtoeol ();
	(void) fflush (stdout);
	seenerr = 0;
	showneed = 0;	/* reset after each update */
	showexpr = 0;

	if ((c < ' ') || ( c == DEL ))
	    switch (c) {
#ifdef SIGTSTP
		case ctl ('z'):
		    deraw();
		    (void) kill(getpid(),SIGTSTP);

		    /* the pc stops here */

		    goraw();
		    break;
#endif
		case ctl ('r'):
		case ctl ('l'):
		    FullUpdate++;
		    if (c == ctl ('r'))
			showneed = 1;
		    (void) clearok(stdscr,1);
		    break;
		case ctl ('x'):
		    FullUpdate++;
		    showexpr = 1;
		    (void) clearok(stdscr,1);
		    break;
		default:
		    error ("No such command (^%c)", c + 0100);
		    break;
		case ctl ('b'):
		    backcol(arg);
		    break;
		case ctl ('c'):
		    running = 0;
		    break;

		case ctl ('e'):

		    switch (nmgetch()) {
		    case ctl ('p'): case 'k':	doend (-1, 0);	break;
		    case ctl ('n'): case 'j':	doend ( 1, 0);	break;

		    case ctl ('b'): case 'h':
		    case ctl ('h'): case ctl ('a'):	doend ( 0,-1);	break;

		    case ctl ('f'): case 'l':
		    case ctl ('e'):
		    case ctl ('i'): case ' ':	doend ( 0, 1);	break;

		    case ESC:
		    case ctl ('g'):
			break;

		    default:
			error("Invalid ^E command");
			break;
		    }

		    break;

		case ctl ('f'):
		    forwcol(arg);
		    break;
		case ctl ('g'):
		case ESC:	/* ctl ('[') */
		    showrange = 0;
		    linelim = -1;
		    (void) move (1, 0);
		    (void) clrtoeol ();
		    break;
		case DEL:
		case ctl ('h'):
		    if (linelim <= 0) {	/* not editing line */
			backcol(arg);	/* treat like ^B    */
			break;
		    }
		    while (--arg>=0) if (linelim > 0)
			line[--linelim] = 0;
		    break;
		case ctl ('i'): 		/* tab */
		    if (linelim <= 0) {	/* not editing line */
			forwcol(arg);
			break;
		    }

		    if (!showrange) {
			startshow();
		    } else {
			showdr();
			linelim = strlen(line);
			line[linelim++] = ' ';
			line[linelim] = 0;
			showrange = 0;
		    }
		    linelim = strlen (line);
		    break;
		case ctl ('m'):
		case ctl ('j'):
		    showrange = 0;
		    if (linelim < 0)
			line[linelim = 0] = 0;
		    else {
			linelim = 0;
			(void) yyparse ();
			linelim = -1;
		    }
		    break;
		case ctl ('n'):
		    forwrow(arg);
		    break;
		case ctl ('p'):
		    backrow(arg);
		    break;
		case ctl ('q'):
		    break;	/* ignore flow control */
		case ctl ('s'):
		    break;	/* ignore flow control */
		case ctl ('t'):
		    error(
"Toggle:  a:auto  c:cell  e:ext funcs  n:numeric  t:top  x:encrypt  $:pre-scale");
		    (void) refresh();

		    switch (nmgetch()) {
			case 'a': case 'A':
			case 'm': case 'M':
			    autocalc ^= 1;
			    error("Automatic recalculation %sabled.",
				autocalc ? "en":"dis");
			    break;
			case 'n': case 'N':
			    numeric = (! numeric);
			    error ("Numeric input %sabled.",
				    numeric ? "en" : "dis");
			    break;
			case 't': case 'T':
			    showtop = (! showtop);
			    repaint(lastmx, lastmy, fwidth[lastcol]);
			    error ("Top line %sabled.", showtop ? "en" : "dis");
			    break;
			case 'c': case 'C':
			    showcell = (! showcell);
			    repaint(lastmx, lastmy, fwidth[lastcol]);
			    error ("Cell highlighting %sabled.",
				    showcell ? "en" : "dis");
			    break;
			case 'x': case 'X':
			    Crypt = (! Crypt);
			    error ("Encryption %sabled.", Crypt? "en" : "dis");
			    break;
			case '$':
			    if (prescale == 1.0) {
				error ("Prescale enabled.");
				prescale = 0.01;
			    } else {
				prescale = 1.0;
				error ("Prescale disabled.");
			    }
			    break;
			case 'e': case 'E':
			    extfunc = (! extfunc);
			    error ("External functions %sabled.",
				    extfunc? "en" : "dis");
			    break;
			case ESC:
			case ctl ('g'):
			    break;
			default:
			    error ("Invalid toggle command");
		    }
		    FullUpdate++;
		    modflg++;
		    break;
		case ctl ('u'):
		    narg = arg * 4;
		    nedistate = 1;
		    break;
		case ctl ('v'):	/* insert variable name */
		    if (linelim > 0) {
		    (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
			linelim = strlen (line);
		    }
		    break;
		case ctl ('w'):	/* insert variable expression */
		    if (linelim > 0) editexp(currow,curcol);
		    break;
		case ctl ('a'):	/* insert variable value */
		    if (linelim > 0) {
			struct ent *p = tbl[currow][curcol];

			if (p && p -> flags & is_valid) {
			    (void) sprintf (line + linelim, "%.*f",
					precision[curcol],p -> v);
			    linelim = strlen (line);
			}
		    }
		    break;
		}
	else
	    if ('0' <= c && c <= '9' && ( (numeric && edistate >= 0) ||
			(!numeric && (linelim < 0 || edistate >= 0))))
	    {
		if (edistate != 0) {
		    if (c == '0')      /* just a '0' goes to left col */
			curcol = 0;
		    else {
		        nedistate = 0;
		        narg = c - '0';
		    }
		} else {
		    nedistate = 0;
		    narg = arg * 10 + (c - '0');
		}
	    }
	    else
		if (linelim >= 0) {     /* Editing line */
		    switch(c) {
			case ')':
			    if (showrange) {
				showdr();
			        showrange = 0;
			        linelim = strlen (line);
			    }
			    break;
		       default:
			    break;
		    }
		    line[linelim++] = c;
		    line[linelim] = 0;
		}
		else if (!numeric && ( c == '+' || c == '-' ) )	
				/* increment/decrement ops */
			{
			    register struct ent *p = tbl[currow][curcol];
			    if (!p)
				break;
			    FullUpdate++;
			    modflg++;
			    if( c == '+' ) p -> v += (double) arg;
			    else p -> v -= (double) arg;
			    }
		else
		    switch (c) {
			case ':':
			    break;	/* Be nice to vi users */

			case '@':
			    EvalAll ();
			    changed = 0;
			    break;

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			case '-': case '.': case '+':
			    (void) sprintf(line,"let %s = %c",
					v_name(currow, curcol), c);
			    linelim = strlen (line);
			    break;

			case '=':
			    (void) sprintf(line,"let %s = ",
						v_name(currow, curcol));
			    linelim = strlen (line);
			    break;

			case '!':
			    {
			    /*
			     *  "! command"  executes command
			     *  "!"	forks a shell
			     *  "!!" repeats last command
			     */
#ifdef VMS
			    error("Not implemented on VMS");
#else /* VMS */
			    char *shl;
			    int pid, temp;
			    char cmd[MAXCMD];
			    static char lastcmd[MAXCMD];

			    if (!(shl = getenv("SHELL")))
				shl = "/bin/sh";

			    deraw();
			    (void) fputs("! ", stdout);
			    (void) fflush(stdout);
			    (void) fgets(cmd, MAXCMD, stdin);
			    cmd[strlen(cmd) - 1] = '\0';	/* clobber \n */
			    if(strcmp(cmd,"!") == 0)		/* repeat? */
				    (void) strcpy(cmd, lastcmd);
			    else
				    (void) strcpy(lastcmd, cmd);

			    if (modflg)
			    {
				(void) puts ("[No write since last change]");
				(void) fflush (stdout);
			    }

			    if (!(pid = fork()))
			    {
				(void) signal (SIGINT, SIG_DFL);  /* reset */
			        if(strlen(cmd))
					(void)execl(shl,shl,"-c",cmd,(char *)0);
				else
					(void) execl(shl, shl, (char *)0);
				exit(-127);
			    }

			    while (pid != wait(&temp));

			    (void) printf("Press RETURN to continue ");
			    (void)nmgetch();
			    goraw();
#endif /* VMS */
			    break;
			    }

			/*
			 * Range commands:
			 */

			case '/':
			    error (
    "Range:  x:erase  v:value  c:copy  f:fill  d:define  s:show  u:undefine");
			    (void) refresh();

			    switch (nmgetch()) {
			    case 'c':
				(void) sprintf(line,"copy [dest_range src_range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'x':
				(void) sprintf(line,"erase [range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'v':
				(void) sprintf(line, "value [range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'f':
				(void) sprintf(line,"fill [range start inc] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'd':
				(void) sprintf(line,"define [string range] \"");
				linelim = strlen(line);
				startshow();
				modflg++;
				break;
			    case 'u':
				(void) sprintf(line,"undefine [range] ");
				linelim = strlen(line);
				modflg++;
				break;
			    case 's':
				if(are_ranges())
				{
				FILE *f;
				int pid;
				char px[MAXCMD] ;
				char *pager;

				(void) strcpy(px, "| sort | ");
				if(!(pager = getenv("PAGER")))
					pager = DFLT_PAGER;
				(void) strcat(px,pager);
				f = openout(px, &pid);
				if (!f) {
				    error("Can't open pipe to sort");
				    break;
				}
				list_range(f);
				closeout(f, pid);
				}
				else error("No ranges defined");
				break;
				
			    case ESC:
			    case ctl ('g'):
				break;
			   default:
				error("Invalid region command");
				break;
			   }
			   break;

			/*
			 * Row/column commands:
			 */

			case 'i':
			case 'a':
			case 'd':
			case 'p':
			case 'v':
			case 'z':
			case 's':
			    {
				register rcqual;

				if (! (rcqual = get_rcqual (c))) {
				    error ("Invalid row/column command");
				    break;
				}

				error ("");	/* clear line */

				if ( rcqual == ESC || rcqual == ctl('g'))
				    break;

				switch (c) {

				case 'i':
				    if (rcqual == 'r')	insertrow (arg);
				    else		insertcol (arg);
				    break;

				case 'a':
				    if (rcqual == 'r')	while (arg--) duprow();
				    else		while (arg--) dupcol();
				    break;

				case 'd':
				    if (rcqual == 'r')	deleterow (arg);
				    else		deletecol (arg);
				    break;

				case 'p':
				    while (arg--)	pullcells (rcqual);
				    break;

				case 'v':
				    if (rcqual == 'r')	rowvalueize (arg);
				    else		colvalueize (arg);
				    modflg = 1;
				    break;

				case 'z':
				    if (rcqual == 'r')	hiderow (arg);
				    else		hidecol (arg);
				    modflg++;
				    break;

				case 's':
				    /* special case; no repeat count */

				    if (rcqual == 'r')	rowshow_op();
				    else		colshow_op();
				    break;
				}
				break;
			    }

			case '$':
			    {
			    register struct ent *p;

			    curcol = MAXCOLS - 1;
			    while (!VALID_CELL(p, currow, curcol) && curcol > 0)
				curcol--;
			    break;
			    }
			case '#':
			    {
			    register struct ent *p;

			    currow = MAXROWS - 1;
			    while (!VALID_CELL(p, currow, curcol) && currow > 0)
				currow--;
			    break;
			    }
			case 'w':
			    {
			    register struct ent *p;

			    while (--arg>=0) {
				do {
				    if (curcol < MAXCOLS - 1)
					curcol++;
				    else {
					if (currow < MAXROWS - 1) {
					    while(++currow < MAXROWS - 1 &&
					            row_hidden[currow]) /* */;
					    curcol = 0;
					} else {
					    error("At end of table");
					    break;
					}
				    }
				} while(col_hidden[curcol] ||
					!VALID_CELL(p, currow, curcol));
			    }
			    break;
			    }
			case 'b':
			    {
			    register struct ent *p;

			    while (--arg>=0) {
				do {
				    if (curcol) 
					curcol--;
				    else {
					if (currow) {
					    while(--currow &&
						row_hidden[currow]) /* */;
					    curcol = MAXCOLS - 1;
					} else {
					    error ("At start of table");
					    break;
					}
				    }
				} while(col_hidden[curcol] ||
					!VALID_CELL(p, currow, curcol));
			    }
			    break;
			    }
			case '^':
			    currow = 0;
			    break;
			case '?':
			    help ();
			    break;
			case '"':
			    (void) sprintf (line, "label %s = \"",
						v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case '<':
			    (void) sprintf (line, "leftstring %s = \"",
				    v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case '>':
			    (void) sprintf (line, "rightstring %s = \"",
				   v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case 'e':
			    editv (currow, curcol);
			    break;
			case 'E':
			    edits (currow, curcol);
			    break;
			case 'f':
			    if (arg == 1)
			        (void) sprintf (line, "format [for column] %s ",
					coltoa(curcol));
			    else {
				(void) sprintf(line, "format [for columns] %s:",
					coltoa(curcol));
				(void) sprintf(line+strlen(line), "%s ",
					coltoa(curcol+arg-1));
			    }
			    error("Current format is %d %d",
					fwidth[curcol],precision[curcol]);
			    linelim = strlen (line);
			    break;
			case 'g':
			    (void) sprintf (line, "goto [v] ");
			    linelim = strlen (line);
			    break;
			case 'P':
			    (void) sprintf (line, "put [\"dest\" range] \"");
			    if (*curfile)
			        error ("Default path is \"%s\"",curfile);
			    linelim = strlen (line);
			    break;
			case 'M':
			    (void) sprintf (line, "merge [\"source\"] \"");
			    linelim = strlen (line);
			    break;
			case 'R':
			    (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
			    linelim = strlen (line);
			    break;
			case 'D':
			    (void) sprintf (line, "mdir [\"macro_directory\"] \"");
			    linelim = strlen (line);
			    break;
			case 'G':
			    (void) sprintf (line, "get [\"source\"] \"");
			    if (*curfile)
			        error ("Default file is \"%s\"",curfile);
			    linelim = strlen (line);
			    break;
			case 'W':
			    (void) sprintf (line, "write [\"dest\" range] \"");
			    linelim = strlen (line);
			    break;
			case 'S':	/* set options */
			    (void) sprintf (line, "set ");
			    error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
			    linelim = strlen (line);
			    break;
			case 'T':	/* tbl output */
			    (void) sprintf (line, "tbl [\"dest\" range] \"");
			    linelim = strlen (line);
			    break;
			case 'x':
			    {
			    register struct ent **p;
			    register int c1;

			    flush_saved();
			    if(calc_order == BYROWS) {
			    for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
				p = &tbl[currow][c1];
				if (*p) {
			            free_ent(*p);
			            *p = 0;
				}
			    }
			    }
			    else {
			    for (c1 = currow; arg-- && c1 < MAXROWS; c1++) {
				p = &tbl[c1][curcol];
				if (*p) {
			            free_ent(*p);
			            *p = 0;
				}
			    }
			    }
			    sync_refs();
			    modflg++;
			    FullUpdate++;
			    }
			    break;
			case 'Q':
			case 'q':
			    running = 0;
			    break;
			case 'h':
			    backcol(arg);
			    break;
			case 'j':
			    forwrow(arg);
			    break;
			case 'k':
			    backrow(arg);
			    break;
			case ' ':
			case 'l':
			    forwcol(arg);
			    break;
			case 'm':
			    savedrow = currow;
			    savedcol = curcol;
			    break;
			case 'c': {
			    register struct ent *p = tbl[savedrow][savedcol];
			    register c1;
			    register struct ent *n;
			    if (!p)
				break;
			    FullUpdate++;
			    modflg++;
			    for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
				n = lookat (currow, c1);
				(void) clearent(n);
				copyent( n, p, currow - savedrow, c1 - savedcol);
			    }
			    break;
			}
			default:
			    if ((c & 0177) != c)	/* doesn't this depend on INTERNATIONAL */
				error ("Weird character, decimal %d\n",
					(int) c);
			    else
				    error ("No such command (%c)", c);
			    break;
		    }
	edistate = nedistate;
	arg = narg;
    }				/* while (running) */
    inloop = modcheck(" before exiting");
    }				/*  while (inloop) */
    deraw();
    endwin();
#ifdef VMS	/* Unit VMS "fixes" exit we should say 1 here */
    exit(1);
#else
    exit(0);
#endif
    /*NOTREACHED*/
}

startshow()
{
    showrange = 1;
    showsr = currow;
    showsc = curcol;
}

showdr()
{
    int     minsr, minsc, maxsr, maxsc;

    minsr = showsr < currow ? showsr : currow;
    minsc = showsc < curcol ? showsc : curcol;
    maxsr = showsr > currow ? showsr : currow;
    maxsc = showsc > curcol ? showsc : curcol;
    (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
}

setorder(i)
int i;
{
	if((i == BYROWS)||(i == BYCOLS))
	    calc_order = i;
	else
	    error("Not yet implemented");
}

setauto(i)
int i;
{
	autocalc = i;
}


#ifdef VMS

goraw()
{
    VMS_read_raw = 1;
    FullUpdate++;
}

deraw()
{
    (void) move (LINES - 1, 0);
    (void) clrtoeol();
    (void) refresh();
    VMS_read_raw = 0;
}

#else /* VMS */

goraw()
{
#if SYSV2 || SYSV3
    fixterm();
#else /* SYSV2 || SYSV3 */
    cbreak();
    nonl();
    noecho ();
#endif /* SYSV2 || SYSV3 */
    kbd_again();
    (void) clear();
    FullUpdate++;
}

deraw()
{
    (void) move (LINES - 1, 0);
    (void) clrtoeol();
    (void) refresh();
#if SYSV2 || SYSV3
    resetterm();
#else
    nocbreak();
    nl();
    echo();
#endif
    resetkbd();
}

#endif /* VMS */

static void
signals(void)
{
#ifdef SIGVOID
    void quit();
    void time_out();
#else
    int quit();
    int time_out();
#endif

    (void) signal(SIGINT, SIG_IGN);
    (void) signal(SIGQUIT, quit);
    (void) signal(SIGPIPE, quit);
    (void) signal(SIGTERM, quit);
    (void) signal(SIGALRM, time_out);
    (void) signal(SIGFPE, quit);
    (void) signal(SIGBUS, quit);
}

#ifdef SIGVOID
void
#endif
quit()
{
    deraw();
    resetkbd();
    endwin();
    exit(1);
}

modcheck(endstr)
char *endstr;
{
    if (modflg && curfile[0]) {
	char ch, lin[100];

	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr);
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
	    error("y or n response required");
	    return (1);
	}
 	if (ch != 'n' && ch != 'N') {
 	    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
 		return (1);
	} else if (ch == ctl ('g') || ch == ESC) return(1);
    } else if (modflg) {
	char ch, lin[100];

	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,"Do you want a chance to save the data? ");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
	    error("y or n response required");
	    return (1);
	}
	if (ch == 'n' || ch == 'N') return(0);
	else return(1);
      }
    return(0);
}

Added sc.h.







































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*	SC	A Table Calculator
 *		Common definitions
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *		R. Bond  12/86
 *		More mods by Alan Silverstein, 3-4/88, see list of changes.
 *		$Revision: 1.1 $
 *
 */

/*
 * These have a private meaning within SC
 */
#undef MIN
#undef MAX

#define MAXROWS 400
#define MAXCOLS 40
#define RESCOL 4  /* columns reserved for row numbers */
#define RESROW 3  /* rows reserved for prompt, error, and column numbers */
#define DEFWIDTH 10 /* Default column width and precision */
#define DEFPREC   2
#define error move(1,0), clrtoeol(), (void) printw

struct ent_ptr {
    int vf;
    struct ent *vp;
};

struct range_s {
	struct ent_ptr left, right;
};

/*
 * If you want to save room, make row and col below into unsigned
 * chars and make sure MAXROWS and MAXCOLS above are both less
 * than 256.  (128 if your compiler doesn't support unsigned char).
 *
 * Some not too obvious things about the flags:
 *    is_valid means there is a valid number in v.
 *    label set means it points to a valid constant string.
 *    is_strexpr set means expr yields a string expression.
 *    If is_strexpr is not set, and expr points to an expression tree, the
 *        expression yields a numeric expression.
 *    So, either v or label can be set to a constant. 
 *        Either (but not both at the same time) can be set from an expression.
 */

#define VALID_CELL(p, r, c) ((p = tbl[r][c])&&((p->flags&is_valid)||p->label))

struct ent {
    double v;
    char *label;
    struct enode *expr;
    short flags;
    short row, col;
    struct ent *next;
};

struct range {
    struct ent_ptr r_left, r_right;
    char *r_name;
    struct range *r_next, *r_prev;
    int r_is_range;
};

#define FIX_ROW 1
#define FIX_COL 2

struct enode {
    int op;
    union {
	double k;
	struct ent_ptr v;
	struct range_s r;
	char *s;
	struct {
	    struct enode *left, *right;
	} o;
    } e;
};

/* op values */
#define O_VAR 'v'
#define O_CONST 'k'
#define O_SCONST '$'
#define REDUCE 0200	/* Or'ed into OP if operand is a range */

#define OP_BASE 256
#define ACOS OP_BASE + 0
#define ASIN OP_BASE + 1
#define ATAN OP_BASE + 2
#define CEIL OP_BASE + 3
#define COS OP_BASE + 4
#define EXP OP_BASE + 5 
#define FABS OP_BASE + 6 
#define FLOOR OP_BASE + 7
#define HYPOT OP_BASE + 8
#define LOG OP_BASE + 9
#define LOG10 OP_BASE + 10
#define POW OP_BASE + 11
#define SIN OP_BASE + 12
#define SQRT OP_BASE + 13
#define TAN OP_BASE + 14
#define DTR OP_BASE + 15
#define RTD OP_BASE + 16
#define MIN OP_BASE + 17
#define MAX OP_BASE + 18
#define RND OP_BASE + 19
#define HOUR OP_BASE + 20
#define MINUTE OP_BASE + 21
#define SECOND OP_BASE + 22
#define MONTH OP_BASE + 23
#define DAY OP_BASE + 24
#define YEAR OP_BASE + 25
#define NOW OP_BASE + 26
#define DATE OP_BASE + 27
#define FMT OP_BASE + 28
#define SUBSTR OP_BASE + 29
#define STON OP_BASE + 30
#define EQS OP_BASE + 31
#define EXT OP_BASE + 32
#define ELIST OP_BASE + 33	/* List of expressions */
#define LMAX  OP_BASE + 34
#define LMIN  OP_BASE + 35
#define NVAL OP_BASE + 36
#define SVAL OP_BASE + 37
#define PV OP_BASE + 38
#define FV OP_BASE + 39
#define PMT OP_BASE + 40
#define STINDEX OP_BASE + 41
#define LOOKUP OP_BASE + 42
#define ATAN2 OP_BASE + 43
#define INDEX OP_BASE + 44
#define STLOOKUP OP_BASE + 45

/* flag values */
#define is_valid     0001
#define is_changed   0002
#define is_strexpr   0004
#define is_leftflush 0010
#define is_deleted   0020

#define ctl(c) ((c) & 037)
#define ESC 033
#define DEL 0177

#define BYCOLS 1
#define BYROWS 2
#define BYGRAPH 4		/* Future */

#define	TBL	1		/* tblprint style output for 'tbl' */
#define	LATEX	2		/* tblprint style output for 'LaTeX' */
#define	TEX	3		/* tblprint style output for 'TeX' */

/* Types for etype() */

#define NUM	1
#define STR	2

extern struct ent *tbl[MAXROWS][MAXCOLS];

extern char curfile[];
extern int strow, stcol;
extern int currow, curcol;
extern int savedrow, savedcol;
extern int FullUpdate;
extern int maxrow, maxcol;
extern int fwidth[MAXCOLS];
extern int precision[MAXCOLS];
extern char col_hidden[MAXCOLS];
extern char row_hidden[MAXROWS];
extern char line[1000];
extern int linelim;
extern int changed;
extern struct ent *to_fix;
extern int showsc, showsr;
extern struct enode *new();
extern struct enode *new_const();
extern struct enode *new_var();
extern struct enode *new_str();
extern struct enode *new_range();
extern struct ent *lookat();
extern struct enode *copye();
extern char *coltoa();
extern FILE *openout();
extern struct range *find_range();
extern char *v_name();
extern char *r_name();
extern double eval();
extern char *seval();
extern int modflg;
extern int Crypt;
extern char *mdir;
extern char *xmalloc();
extern int xfree();
extern double prescale;
extern int extfunc;
extern int propagation;
extern int calc_order;
extern int autocalc;
extern int numeric;
extern int showcell;
extern int showtop;
extern int loading;
extern int tbl_style;
extern char *progname;

#if BSD42 || SYSIII

#ifndef cbreak
#define	cbreak		crmode
#define	nocbreak	nocrmode
#endif

#endif

extern void clearent(struct ent *);
extern void editexp(int row, int col);
extern void showstring (char *string,
    int leftflush, int hasvalue, int row, int col,
    int *nextcolp, int mxcol, int *fieldlenp,
    int r, int c);
extern void initkbd(void);
extern void readfile (char *fname, int eraseflg);

Added sc_vax.c.





























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
/*	SC	A Spreadsheet Calculator
 *		Main driver
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *		More mods by Alan Silverstein, 3-4/88, see list of changes.
 *
 */


#include <signal.h>
#include <curses.h>

#ifdef BSD42
#undef nl
#undef nonl
#define nl()	 (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
#define nonl()	 (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
#endif

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include <stdio.h>
#include "sc.h"

char *getenv();

#ifdef SYSV3
void exit();
#endif

/*
 * CODE REVISION NUMBER:
 *
 * The part after the first colon, except the last char, appears on the screen.
 */

char *rev = "$Revision: 1.1 $";

#ifndef DFLT_PAGER
#define	DFLT_PAGER "more"	/* more is probably more widespread than less */
#endif /* DFLT_PAGER */

#define MAXCMD 160	/* for ! command below */

/* Globals defined in sc.h */

struct ent *tbl[MAXROWS][MAXCOLS];
int strow, stcol;
int currow, curcol;
int savedrow, savedcol;
int FullUpdate;
int maxrow, maxcol;
int fwidth[MAXCOLS];
int precision[MAXCOLS];
char col_hidden[MAXCOLS];
char row_hidden[MAXROWS];
char line[1000];
int changed;
struct ent *to_fix;
int modflg;
int numeric;
char *mdir;
int showsc, showsr;	/* Starting cell for highlighted range */

char curfile[1024];
char    revmsg[80];

int  linelim = -1;

int  showtop   = 1;	/* Causes current cell value display in top line  */
int  showcell  = 1;	/* Causes current cell to be highlighted	  */
int  showrange = 0;	/* Causes ranges to be highlighted		  */
int  showneed  = 0;	/* Causes cells needing values to be highlighted  */
int  showexpr  = 0;	/* Causes cell exprs to be displayed, highlighted */

int  autocalc = 1 ;	/* 1 to calculate after each update */
int  calc_order = BYROWS;
int  tbl_style = 0;	/* headers for T command output */

int  lastmx, lastmy;	/* Screen address of the cursor */
int  lastcol;		/* Spreadsheet Column the cursor was in last */
char *under_cursor = " "; /* Data under the < cursor */

#ifdef VMS
int VMS_read_raw = 0;
#endif

int seenerr;

yyerror (err)
char *err; {
    if (seenerr) return;
    seenerr++;
    (void) move (1,0);
    (void) clrtoeol ();
    (void) printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
}

struct ent *
lookat(row,col){
    register struct ent **p;
    if (row < 0)
	row = 0;
    else if (row > MAXROWS-1) 
	row = MAXROWS-1;
    if (col < 0) 
	col = 0;
    else if (col > MAXCOLS-1)
	col = MAXCOLS-1;
    p = &tbl[row][col];
    if (*p==0) {
	*p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent));
	if (row>maxrow) maxrow = row;
	if (col>maxcol) maxcol = col;
	(*p)->label = 0;
	(*p)->flags = 0;
	(*p)->row = row;
	(*p)->col = col;
	(*p)->expr = 0;
	(*p)->v = (double) 0.0;
    }
    return *p;
}

/*
 * This structure is used to keep ent structs around before they
 * are deleted to allow the sync_refs routine a chance to fix the
 * variable references.
 * We also use it as a last-deleted buffer for the 'p' command.
 */

free_ent(p)
register struct ent *p;
{
    p->next = to_fix;
    to_fix = p;
    p->flags |= is_deleted;
}

flush_saved()
{
    register struct ent *p;
    register struct ent *q;

    if (!(p = to_fix))
	return;
    while (p) {
	(void) clearent(p);
	q = p->next;
	xfree((char *)p);
	p = q;
    }
    to_fix = 0;
}

update ()
{
    register    row,
                col;
    register struct ent **p;
    int     mxcol;
    int     mxrow;
    int     rows;
    int     cols;
    int     minsr, minsc, maxsr, maxsc;
    register r;
    register i;

    while (row_hidden[currow])   /* You can't hide the last row or col */
	currow++;
    while (col_hidden[curcol])
	curcol++;
    /* First see if the last display still covers curcol */
    if (stcol <= curcol) { 
	for (i = stcol, cols = 0, col = RESCOL;
			(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (col_hidden[i])
		continue;
	    col += fwidth[i];
	}
    }
    while (stcol + cols - 1 < curcol || curcol < stcol) {
	FullUpdate++;
	if (stcol - 1 == curcol) {    /* How about back one? */
	    stcol--;
	} else if (stcol + cols == curcol) {   /* Forward one? */
	    stcol++;
	} else {
	    /* Try to put the cursor in the center of the screen */
	    col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
	    stcol = curcol;
	    for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
		stcol--;
		if (col_hidden[i])
		    continue;
		col -= fwidth[i];
	    }
	}
	/* Now pick up the counts again */
	for (i = stcol, cols = 0, col = RESCOL;
			(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (col_hidden[i])
		continue;
	    col += fwidth[i];
	}
    }
    /* Now - same process on the rows */
    if (strow <= currow) { 
	for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
	    rows++;
	    if (row_hidden[i])
		continue;
	    row++;
	}
    }
    while (strow + rows - 1 < currow || currow < strow) {
	FullUpdate++;
	if (strow - 1 == currow) {    /* How about up one? */
	    strow--;
	} else if (strow + rows == currow) {   /* Down one? */
	    strow++;
	} else {
	    /* Try to put the cursor in the center of the screen */
	    row = (LINES - RESROW) / 2 + RESROW; 
	    strow = currow;
	    for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
		strow--;
		if (row_hidden[i])
		    continue;
		row--;
	    }
	}
	/* Now pick up the counts again */
	for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
	    rows++;
	    if (row_hidden[i])
		continue;
	    row++;
	}
    }
    mxcol = stcol + cols - 1;
    mxrow = strow + rows - 1;
    if (FullUpdate) {
	(void) move (2, 0);
	(void) clrtobot ();
	(void) standout();
	for (row=RESROW, i=strow; i <= mxrow; i++) {
	    if (row_hidden[i]) 
		continue;
	    (void) move(row,0);
#if MAXROW < 1000
	    (void) printw("%-*d", RESCOL-1, i);
#else
	    (void) printw("%-*d", RESCOL, i);
#endif
	    row++;
	}
	(void) move (2,0);
	(void) printw("%*s", RESCOL, " ");
	for (col=RESCOL, i = stcol; i <= mxcol; i++) {
	    register int k;
	    if (col_hidden[i])
		continue;
	    (void) move(2, col);
	    k = fwidth[i]/2;
	    if (k == 0)
		(void) printw("%1s", coltoa(i));
	    else
	        (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
	    col += fwidth[i];
	}
	(void) standend();
    }

    /* Get rid of cursor standout on the cell at previous cursor position */
    (void) move(lastmx, lastmy);
    if (showcell)
        repaint(lastmx, lastmy, fwidth[lastcol]);

    if (showrange) {
	minsr = showsr < currow ? showsr : currow;
	minsc = showsc < curcol ? showsc : curcol;
	maxsr = showsr > currow ? showsr : currow;
	maxsc = showsc > curcol ? showsc : curcol;

	if (showtop) {
	    (void) move(1,0);
	    (void) clrtoeol();
	    (void) printw("Default range:  %s",
			    r_name(minsr, minsc, maxsr, maxsc));
	}
    }

    /* Repaint the visible screen */
    for (row = strow, r = RESROW; row <= mxrow; row++) {
	register c = RESCOL;
	int do_stand = 0;
	int fieldlen;
	int nextcol;

	if (row_hidden[row])
	    continue;
	for (p = &tbl[row][col = stcol]; col <= mxcol;
	         p += nextcol - col,  col = nextcol, c += fieldlen) {

	    nextcol = col+1;
	    if (col_hidden[col]) {
		fieldlen = 0;
		continue;
	    }

	    fieldlen = fwidth[col];

	    /*
	     * Set standout if:
	     *
	     * - showing ranges, and not showing cells which need to be filled
	     *   in, and not showing cell expressions, and in a range, OR
	     *
	     * - if showing cells which need to be filled in and this one is
	     *   of that type (has a value and doesn't have an expression, or
	     *   it is a string expression), OR
	     *
	     * - if showing cells which have expressions and this one does.
	     */

	    if ((showrange && (! showneed) && (! showexpr)
			   && (row >= minsr) && (row <= maxsr)
			   && (col >= minsc) && (col <= maxsc))

	     || (showneed && (*p) && ((*p) -> flags & is_valid)
	      && (((*p) -> flags & is_strexpr) || ! ((*p) -> expr)))

	     || (showexpr && (*p) && ((*p) -> expr)))
	    {
		do_stand = 1;
	    }

	    if (*p && ((*p) -> flags & is_changed || FullUpdate) || do_stand) {
		(void) move (r, c);
		if (!*p)
		    *p = lookat(row, col);
		if (do_stand) {
		    (void) standout();
		    (*p) -> flags |= is_changed; 
		} else {
		    (*p) -> flags &= ~is_changed;
		}

		/*
		 * Show expression; takes priority over other displays:
		 */

		if (showexpr && ((*p) -> expr)) {
		    linelim = 0;
		    editexp (row, col);		/* set line to expr */
		    linelim = -1;
		    showstring (line, /* leftflush = */ 1, /* hasvalue = */ 0,
				row, col, & nextcol, mxcol, & fieldlen, r, c);
		}
		else {

		    /*
		     * Show cell's numeric value:
		     */

		    if ((*p) -> flags & is_valid) {
			char field[1024];
			(void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*p)->v);
			if(strlen(field) > fwidth[col]) {
			    for(i = 0; i<fwidth[col]; i++)
				(void)addch('*');
			} else {
			    (void)addstr(field);
			}
		    }

		    /*
		     * Show cell's label string:
		     */

		    if ((*p) -> label) {
			showstring ((*p) -> label,
				    (*p) -> flags & is_leftflush,
				    (*p) -> flags & is_valid,
				    row, col, & nextcol, mxcol,
				    & fieldlen, r, c);
		    }

		    /*
		     * repaint a blank cell:
		     */

		    if (!((*p)->flags & is_valid) && !(*p)->label) {
			(void) printw ("%*s", fwidth[col], " ");
		    }
		} /* else */

		if (do_stand) {
		    (void) standend();
		    do_stand = 0;
		}
	    }
	}
	r++;
    }
	    
    (void) move(lastmy, lastmx+fwidth[lastcol]);
#ifndef INTERNATIONAL
    if((inch() & 0x7f) == '<')
#else
    if((inch() & 0xff) == '<')
#endif /* INTERNATIONAL */
        (void) addstr(under_cursor);
    lastmy =  RESROW;
    for (row = strow; row < currow; row++)
	if (!row_hidden[row])
		lastmy += 1;
    lastmx = RESCOL;
    for (col = stcol; col < curcol; col++)
	if (!col_hidden[col])
		lastmx += fwidth[col];
    lastcol = curcol;
    (void) move(lastmx, lastmy);
    if (showcell && (! showneed) && (! showexpr)) {
        (void) standout();
        repaint(lastmx, lastmy, fwidth[lastcol]);
        (void) standend();
    }
    (void) move(lastmy, lastmx+fwidth[lastcol]);
#ifndef INTERNATIONAL /*changed to make consistent with all other uses of INTERNATIONAL */
    *under_cursor = (inch() & 0x7f);
#else
    *under_cursor = (inch() & 0xff);
#endif /* INTERNATIONAL */
    (void) addstr("<");

    (void) move (0, 0);
    (void) clrtoeol ();
    if (linelim >= 0) {
	(void) addstr (">> ");
	(void) addstr (line);
    } else {
	if (showtop) {			/* show top line */
	    register struct ent *p1;
	    int printed = 0;		/* printed something? */

            (void) printw ("%s%d ", coltoa (curcol), currow);

	    if (p1 = tbl [currow] [curcol])
	    {
		if (p1 -> expr)		/* has expr of some type */
		{
		    linelim = 0;
		    editexp (currow, curcol);	/* set line to expr */
		    linelim = -1;
		}

		/*
		 * Display string part of cell:
		 */

		if ((p1 -> expr) && (p1 -> flags & is_strexpr))
		{
		    (void) addstr ((p1 -> flags & is_leftflush) ? "<{" : ">{");
		    (void) addstr (line);
		    (void) addstr ("} ");	/* and this '}' is for vi % */
		    printed = 1;
		}
		else if (p1 -> label)		/* has constant label only */
		{
		    (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\"");
		    (void) addstr (p1 -> label);
		    (void) addstr ("\" ");
		    printed = 1;
		}

		/*
		 * Display value part of cell:
		 */

		if (p1 -> flags & is_valid)	/* has value or num expr */
		{
		    if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr))
			(void) sprintf (line, "%.15g", p1 -> v);

		    (void) addstr ("[");
		    (void) addstr (line);
		    (void) addstr ("]");
		    printed = 1;
		}
	    }

	    if (! printed)
		(void) addstr ("[]");
	}
	(void) move (lastmy, lastmx + fwidth[lastcol]);
    }
    if (revmsg[0]) {
	(void) move(0, 0);
	(void) clrtoeol ();	/* get rid of topline display */
	(void) printw(revmsg);
	revmsg[0] = 0;		/* don't show it again */
	(void) move (lastmy, lastmx + fwidth[lastcol]);
    }
    FullUpdate = 0;
}

repaint(x, y, len)
int x, y, len;
{
    char *buf;

    buf = " ";

    while(len-- > 0) {
	(void) move(y,x);
#ifndef INTERNATIONAL
	*buf = inch() & 0x7f;
#else
	*buf = inch() & 0xff;
#endif /* INTERNATIONAL */
	(void) addstr(buf);
	x++;
    }
}

char    *progname;

main (argc, argv)
int argc;
char  **argv;
{
    int     inloop = 1;
    register int   c;
    int     edistate = -1;
    int     arg = 1;
    int     narg;
    int     nedistate;
    int	    running;
    char    *revi;

    /*
     * Keep command line options around until the file is read so the
     * command line overrides file options
     */

    int Mopt = 0;
    int Nopt = 0;
    int Copt = 0; 
    int Ropt = 0;

    progname = argv[0];
    while (argc > 1 && argv[1][0] == '-') {
	argv++;
	argc--;
    	switch (argv[0][1]) {
	    case 'x':
#ifdef VMS
		    (void) fprintf(stderr, "Crypt not available for VMS\n");
		    exit(1);
#else 
		    Crypt = 1;
#endif
		    break;
	    case 'm':
		    Mopt = 1;
		    break;
	    case 'n':
		    Nopt = 1;
		    break;
	    case 'c':
		    Copt = 1;
		    break;
	    case 'r':
		    Ropt = 1;
		    break;
	    default:
		    (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n",
			progname,argv[0][1]);
		    exit(1);
	}
    }

    {
	register    i;
	for (i = 0; i < MAXCOLS; i++) {
	    fwidth[i] = DEFWIDTH;
	    precision[i] = DEFPREC;
	}
    }
    curfile[0]=0;

    signals();
    (void) initscr();
    (void) clear();
#ifdef VMS
    VMS_read_raw = 1;
#else
    nonl();
    noecho ();
    cbreak();
#endif
    initkbd();


    /*
     * Build revision message for later use:
     */

    (void) strcpy (revmsg, progname);
    for (revi = rev; (*revi++) != ':'; );	/* copy after colon */
    (void) strcat (revmsg, revi);
    revmsg [strlen (revmsg) - 2] = 0;		/* erase last character */
    (void) strcat (revmsg, ":  Type '?' for help.");

    if (argc > 1) {
	(void) strcpy(curfile,argv[1]);
	readfile (argv[1], 0);
    }

    if (Mopt)
	autocalc = 0;
    if (Nopt)
	numeric = 1;
    if (Copt)
	calc_order = BYCOLS;
    if (Ropt)
	calc_order = BYROWS;

    modflg = 0;
#ifdef VENIX
    setbuf (stdin, NULL);
#endif
    FullUpdate++;
    while (inloop) { running = 1;
    while (running) {
	nedistate = -1;
	narg = 1;
	if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate))
	    EvalAll (), changed = 0;
	update();
#ifndef SYSV3
	(void) refresh(); /* 5.3 does a refresh in getch */ 
#endif
	c = nmgetch();
	(void) move (1, 0);
	(void) clrtoeol ();
	(void) fflush (stdout);
	seenerr = 0;
	showneed = 0;	/* reset after each update */
	showexpr = 0;

	if ((c < ' ') || ( c == DEL ))
	    switch (c) {
#ifdef SIGTSTP
		case ctl (z):
		    deraw();
		    (void) kill(getpid(),SIGTSTP);

		    /* the pc stops here */

		    goraw();
		    break;
#endif
		case ctl (r):
		case ctl (l):
		    FullUpdate++;
		    if (c == ctl (r))
			showneed = 1;
		    (void) clearok(stdscr,1);
		    break;
		case ctl (x):
		    FullUpdate++;
		    showexpr = 1;
		    (void) clearok(stdscr,1);
		    break;
		default:
		    error ("No such command (^%c)", c + 0100);
		    break;
		case ctl (b):
		    backcol(arg);
		    break;
		case ctl (c):
		    running = 0;
		    break;

		case ctl (e):

		    switch (nmgetch()) {
		    case ctl (p): case 'k':	doend (-1, 0);	break;
		    case ctl (n): case 'j':	doend ( 1, 0);	break;
		    case ctl (b): case 'h':
		    case ctl (h):		doend ( 0,-1);	break;
		    case ctl (f): case 'l':
		    case ctl (i): case ' ':	doend ( 0, 1);	break;

		    case ESC:
		    case ctl (g):
			break;

		    default:
			error("Invalid ^E command");
			break;
		    }

		    break;

		case ctl (f):
		    forwcol(arg);
		    break;
		case ctl (g):
		case ESC:	/* ctl ([) */
		    showrange = 0;
		    linelim = -1;
		    (void) move (1, 0);
		    (void) clrtoeol ();
		    break;
		case DEL:
		case ctl (h):
		    if (linelim <= 0) {	/* not editing line */
			backcol(arg);	/* treat like ^B    */
			break;
		    }
		    while (--arg>=0) if (linelim > 0)
			line[--linelim] = 0;
		    break;
		case ctl (i): 		/* tab */
		    if (linelim <= 0) {	/* not editing line */
			forwcol(arg);
			break;
		    }

		    if (!showrange) {
			startshow();
		    } else {
			showdr();
			linelim = strlen(line);
			line[linelim++] = ' ';
			line[linelim] = 0;
			showrange = 0;
		    }
		    linelim = strlen (line);
		    break;
		case ctl (m):
		case ctl (j):
		    showrange = 0;
		    if (linelim < 0)
			line[linelim = 0] = 0;
		    else {
			linelim = 0;
			(void) yyparse ();
			linelim = -1;
		    }
		    break;
		case ctl (n):
		    forwrow(arg);
		    break;
		case ctl (p):
		    backrow(arg);
		    break;
		case ctl (q):
		    break;	/* ignore flow control */
		case ctl (s):
		    break;	/* ignore flow control */
		case ctl (t):
		    error(
"Toggle:  a:auto  c:cell  e:ext funcs  n:numeric  t:top  x:encrypt  $:pre-scale");
		    (void) refresh();

		    switch (nmgetch()) {
			case 'a': case 'A':
			case 'm': case 'M':
			    autocalc ^= 1;
			    error("Automatic recalculation %sabled.",
				autocalc ? "en":"dis");
			    break;
			case 'n': case 'N':
			    numeric = (! numeric);
			    error ("Numeric input %sabled.",
				    numeric ? "en" : "dis");
			    break;
			case 't': case 'T':
			    showtop = (! showtop);
			    repaint(lastmx, lastmy, fwidth[lastcol]);
			    error ("Top line %sabled.", showtop ? "en" : "dis");
			    break;
			case 'c': case 'C':
			    showcell = (! showcell);
			    repaint(lastmx, lastmy, fwidth[lastcol]);
			    error ("Cell highlighting %sabled.",
				    showcell ? "en" : "dis");
			    break;
			case 'x': case 'X':
			    Crypt = (! Crypt);
			    error ("Encryption %sabled.", Crypt? "en" : "dis");
			    break;
			case '$':
			    if (prescale == 1.0) {
				error ("Prescale enabled.");
				prescale = 0.01;
			    } else {
				prescale = 1.0;
				error ("Prescale disabled.");
			    }
			    break;
			case 'e': case 'E':
			    extfunc = (! extfunc);
			    error ("External functions %sabled.",
				    extfunc? "en" : "dis");
			    break;
			case ESC:
			case ctl (g):
			    break;
			default:
			    error ("Invalid toggle command");
		    }
		    FullUpdate++;
		    modflg++;
		    break;
		case ctl (u):
		    narg = arg * 4;
		    nedistate = 1;
		    break;
		case ctl (v):	/* insert variable name */
		    if (linelim > 0) {
		    (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
			linelim = strlen (line);
		    }
		    break;
		case ctl (w):	/* insert variable expression */
		    if (linelim > 0) editexp(currow,curcol);
		    break;
		case ctl (a):	/* insert variable value */
		    if (linelim > 0) {
			struct ent *p = tbl[currow][curcol];

			if (p && p -> flags & is_valid) {
			    (void) sprintf (line + linelim, "%.*f",
					precision[curcol],p -> v);
			    linelim = strlen (line);
			}
		    }
		    break;
		}
	else
	    if ('0' <= c && c <= '9' && ( (numeric && edistate >= 0) ||
			(!numeric && (linelim < 0 || edistate >= 0))))
	    {
		if (edistate != 0) {
		    if (c == '0')      /* just a '0' goes to left col */
			curcol = 0;
		    else {
		        nedistate = 0;
		        narg = c - '0';
		    }
		} else {
		    nedistate = 0;
		    narg = arg * 10 + (c - '0');
		}
	    }
	    else
		if (linelim >= 0) {     /* Editing line */
		    switch(c) {
			case ')':
			    if (showrange) {
				showdr();
			        showrange = 0;
			        linelim = strlen (line);
			    }
			    break;
		       default:
			    break;
		    }
		    line[linelim++] = c;
		    line[linelim] = 0;
		}
		else if (!numeric && ( c == '+' || c == '-' ) )	
				/* increment/decrement ops */
			{
			    register struct ent *p = tbl[currow][curcol];
			    if (!p)
				break;
			    FullUpdate++;
			    modflg++;
			    if( c == '+' ) p -> v += (double) arg;
			    else p -> v -= (double) arg;
			    }
		else
		    switch (c) {
			case ':':
			    break;	/* Be nice to vi users */

			case '@':
			    EvalAll ();
			    changed = 0;
			    break;

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			case '-': case '.': case '+':
			    (void) sprintf(line,"let %s = %c",
					v_name(currow, curcol), c);
			    linelim = strlen (line);
			    break;

			case '=':
			    (void) sprintf(line,"let %s = ",
						v_name(currow, curcol));
			    linelim = strlen (line);
			    break;

			case '!':
			    {
			    /*
			     *  "! command"  executes command
			     *  "!"	forks a shell
			     *  "!!" repeats last command
			     */
#ifdef VMS
			    error("Not implemented on VMS");
#else /* VMS */
			    char *shl;
			    int pid, temp;
			    char cmd[MAXCMD];
			    static char lastcmd[MAXCMD];

			    if (!(shl = getenv("SHELL")))
				shl = "/bin/sh";

			    deraw();
			    (void) fputs("! ", stdout);
			    (void) fflush(stdout);
			    (void) fgets(cmd, MAXCMD, stdin);
			    cmd[strlen(cmd) - 1] = '\0';	/* clobber \n */
			    if(strcmp(cmd,"!") == 0)		/* repeat? */
				    (void) strcpy(cmd, lastcmd);
			    else
				    (void) strcpy(lastcmd, cmd);

			    if (modflg)
			    {
				(void) puts ("[No write since last change]");
				(void) fflush (stdout);
			    }

			    if (!(pid = fork()))
			    {
				(void) signal (SIGINT, SIG_DFL);  /* reset */
			        if(strlen(cmd))
					(void)execl(shl,shl,"-c",cmd,(char *)0);
				else
					(void) execl(shl, shl, (char *)0);
				exit(-127);
			    }

			    while (pid != wait(&temp));

			    (void) printf("Press RETURN to continue ");
			    (void)nmgetch();
			    goraw();
#endif /* VMS */
			    break;
			    }

			/*
			 * Range commands:
			 */

			case '/':
			    error (
    "Range:  x:erase  v:value  c:copy  f:fill  d:define  s:show  u:undefine");
			    (void) refresh();

			    switch (nmgetch()) {
			    case 'c':
				(void) sprintf(line,"copy [dest_range src_range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'x':
				(void) sprintf(line,"erase [range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'v':
				(void) sprintf(line, "value [range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'f':
				(void) sprintf(line,"fill [range start inc] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'd':
				(void) sprintf(line,"define [string range] \"");
				linelim = strlen(line);
				startshow();
				modflg++;
				break;
			    case 'u':
				(void) sprintf(line,"undefine [range] ");
				linelim = strlen(line);
				modflg++;
				break;
			    case 's':
				if(are_ranges())
				{
				FILE *f;
				int pid;
				char px[MAXCMD] ;
				char *pager;

				(void) strcpy(px, "| sort | ");
				if(!(pager = getenv("PAGER")))
					pager = DFLT_PAGER;
				(void) strcat(px,pager);
				f = openout(px, &pid);
				if (!f) {
				    error("Can't open pipe to sort");
				    break;
				}
				list_range(f);
				closeout(f, pid);
				}
				else error("No ranges defined");
				break;
				
			    case ESC:
			    case ctl (g):
				break;
			   default:
				error("Invalid region command");
				break;
			   }
			   break;

			/*
			 * Row/column commands:
			 */

			case 'i':
			case 'a':
			case 'd':
			case 'p':
			case 'v':
			case 'z':
			case 's':
			    {
				register rcqual;

				if (! (rcqual = get_rcqual (c))) {
				    error ("Invalid row/column command");
				    break;
				}

				error ("");	/* clear line */

				if ( rcqual == ESC || rcqual == ctl(g))
				    break;

				switch (c) {

				case 'i':
				    if (rcqual == 'r')	insertrow (arg);
				    else		insertcol (arg);
				    break;

				case 'a':
				    if (rcqual == 'r')	while (arg--) duprow();
				    else		while (arg--) dupcol();
				    break;

				case 'd':
				    if (rcqual == 'r')	deleterow (arg);
				    else		deletecol (arg);
				    break;

				case 'p':
				    while (arg--)	pullcells (rcqual);
				    break;

				case 'v':
				    if (rcqual == 'r')	rowvalueize (arg);
				    else		colvalueize (arg);
				    modflg = 1;
				    break;

				case 'z':
				    if (rcqual == 'r')	hiderow (arg);
				    else		hidecol (arg);
				    modflg++;
				    break;

				case 's':
				    /* special case; no repeat count */

				    if (rcqual == 'r')	rowshow_op();
				    else		colshow_op();
				    break;
				}
				break;
			    }

			case '$':
			    {
			    register struct ent *p;

			    curcol = MAXCOLS - 1;
			    while (!VALID_CELL(p, currow, curcol) && curcol > 0)
				curcol--;
			    break;
			    }
			case '#':
			    {
			    register struct ent *p;

			    currow = MAXROWS - 1;
			    while (!VALID_CELL(p, currow, curcol) && currow > 0)
				currow--;
			    break;
			    }
			case 'w':
			    {
			    register struct ent *p;

			    while (--arg>=0) {
				do {
				    if (curcol < MAXCOLS - 1)
					curcol++;
				    else {
					if (currow < MAXROWS - 1) {
					    while(++currow < MAXROWS - 1 &&
					            row_hidden[currow]) /* */;
					    curcol = 0;
					} else {
					    error("At end of table");
					    break;
					}
				    }
				} while(col_hidden[curcol] ||
					!VALID_CELL(p, currow, curcol));
			    }
			    break;
			    }
			case 'b':
			    {
			    register struct ent *p;

			    while (--arg>=0) {
				do {
				    if (curcol) 
					curcol--;
				    else {
					if (currow) {
					    while(--currow &&
						row_hidden[currow]) /* */;
					    curcol = MAXCOLS - 1;
					} else {
					    error ("At start of table");
					    break;
					}
				    }
				} while(col_hidden[curcol] ||
					!VALID_CELL(p, currow, curcol));
			    }
			    break;
			    }
			case '^':
			    currow = 0;
			    break;
			case '?':
			    help ();
			    break;
			case '"':
			    (void) sprintf (line, "label %s = \"",
						v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case '<':
			    (void) sprintf (line, "leftstring %s = \"",
				    v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case '>':
			    (void) sprintf (line, "rightstring %s = \"",
				   v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case 'e':
			    editv (currow, curcol);
			    break;
			case 'E':
			    edits (currow, curcol);
			    break;
			case 'f':
			    if (arg == 1)
			        (void) sprintf (line, "format [for column] %s ",
					coltoa(curcol));
			    else {
				(void) sprintf(line, "format [for columns] %s:",
					coltoa(curcol));
				(void) sprintf(line+strlen(line), "%s ",
					coltoa(curcol+arg-1));
			    }
			    error("Current format is %d %d",
					fwidth[curcol],precision[curcol]);
			    linelim = strlen (line);
			    break;
			case 'g':
			    (void) sprintf (line, "goto [v] ");
			    linelim = strlen (line);
			    break;
			case 'P':
			    (void) sprintf (line, "put [\"dest\" range] \"");
			    if (*curfile)
			        error ("Default path is \"%s\"",curfile);
			    linelim = strlen (line);
			    break;
			case 'M':
			    (void) sprintf (line, "merge [\"source\"] \"");
			    linelim = strlen (line);
			    break;
			case 'R':
			    (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
			    linelim = strlen (line);
			    break;
			case 'D':
			    (void) sprintf (line, "mdir [\"macro_directory\"] \"");
			    linelim = strlen (line);
			    break;
			case 'G':
			    (void) sprintf (line, "get [\"source\"] \"");
			    if (*curfile)
			        error ("Default file is \"%s\"",curfile);
			    linelim = strlen (line);
			    break;
			case 'W':
			    (void) sprintf (line, "write [\"dest\" range] \"");
			    linelim = strlen (line);
			    break;
			case 'S':	/* set options */
			    (void) sprintf (line, "set ");
			    error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
			    linelim = strlen (line);
			    break;
			case 'T':	/* tbl output */
			    (void) sprintf (line, "tbl [\"dest\" range] \"");
			    linelim = strlen (line);
			    break;
			case 'x':
			    {
			    register struct ent **p;
			    register int c1;

			    flush_saved();
			    if(calc_order == BYROWS) {
			    for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
				p = &tbl[currow][c1];
				if (*p) {
			            free_ent(*p);
			            *p = 0;
				}
			    }
			    }
			    else {
			    for (c1 = currow; arg-- && c1 < MAXROWS; c1++) {
				p = &tbl[c1][curcol];
				if (*p) {
			            free_ent(*p);
			            *p = 0;
				}
			    }
			    }
			    sync_refs();
			    modflg++;
			    FullUpdate++;
			    }
			    break;
			case 'Q':
			case 'q':
			    running = 0;
			    break;
			case 'h':
			    backcol(arg);
			    break;
			case 'j':
			    forwrow(arg);
			    break;
			case 'k':
			    backrow(arg);
			    break;
			case ' ':
			case 'l':
			    forwcol(arg);
			    break;
			case 'm':
			    savedrow = currow;
			    savedcol = curcol;
			    break;
			case 'c': {
			    register struct ent *p = tbl[savedrow][savedcol];
			    register c1;
			    register struct ent *n;
			    if (!p)
				break;
			    FullUpdate++;
			    modflg++;
			    for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
				n = lookat (currow, c1);
				(void) clearent(n);
				copyent( n, p, currow - savedrow, c1 - savedcol);
			    }
			    break;
			}
			default:
			    if ((c & 0177) != c)	/* doesn't this depend on INTERNATIONAL */
				error ("Weird character, decimal %d\n",
					(int) c);
			    else
				    error ("No such command (%c)", c);
			    break;
		    }
	edistate = nedistate;
	arg = narg;
    }				/* while (running) */
    inloop = modcheck(" before exiting");
    }				/*  while (inloop) */
    deraw();
    endwin();
#ifdef VMS	/* Unit VMS "fixes" exit we should say 1 here */
    exit(1);
#else
    exit(0);
#endif
    /*NOTREACHED*/
}

startshow()
{
    showrange = 1;
    showsr = currow;
    showsc = curcol;
}

showdr()
{
    int     minsr, minsc, maxsr, maxsc;

    minsr = showsr < currow ? showsr : currow;
    minsc = showsc < curcol ? showsc : curcol;
    maxsr = showsr > currow ? showsr : currow;
    maxsc = showsc > curcol ? showsc : curcol;
    (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
}

setorder(i)
int i;
{
	if((i == BYROWS)||(i == BYCOLS))
	    calc_order = i;
	else
	    error("Not yet implemented");
}

setauto(i)
int i;
{
	autocalc = i;
}


#ifdef VMS

goraw()
{
    VMS_read_raw = 1;
    FullUpdate++;
}

deraw()
{
    (void) move (LINES - 1, 0);
    (void) clrtoeol();
    (void) refresh();
    VMS_read_raw = 0;
}

#else /* VMS */

goraw()
{
#if SYSV2 || SYSV3
    fixterm();
#else /* SYSV2 || SYSV3 */
    cbreak();
    nonl();
    noecho ();
#endif /* SYSV2 || SYSV3 */
    kbd_again();
    (void) clear();
    FullUpdate++;
}

deraw()
{
    (void) move (LINES - 1, 0);
    (void) clrtoeol();
    (void) refresh();
#if SYSV2 || SYSV3
    resetterm();
#else
    nocbreak();
    nl();
    echo();
#endif
    resetkbd();
}

#endif /* VMS */

signals()
{
#ifdef SIGVOID
    void quit();
    void time_out();
#else
    int quit();
    int time_out();
#endif

    (void) signal(SIGINT, SIG_IGN);
    (void) signal(SIGQUIT, quit);
    (void) signal(SIGPIPE, quit);
    (void) signal(SIGTERM, quit);
    (void) signal(SIGALRM, time_out);
    (void) signal(SIGFPE, quit);
    (void) signal(SIGBUS, quit);
}

#ifdef SIGVOID
void
#endif
quit()
{
    deraw();
    resetkbd();
    endwin();
    exit(1);
}

modcheck(endstr)
char *endstr;
{
    if (modflg && curfile[0]) {
	char ch, lin[100];

	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr);
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
	    error("y or n response required");
	    return (1);
	}
 	if (ch != 'n' && ch != 'N') {
 	    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
 		return (1);
	} else if (ch == ctl (g) || ch == ESC) return(1);
    } else if (modflg) {
	char ch, lin[100];

	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,"Do you want a chance to save the data? ");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
	    error("y or n response required");
	    return (1);
	}
	if (ch == 'n' || ch == 'N') return(0);
	else return(1);
      }
    return(0);
}

Added statres.h.











































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
	"FORMAT",	S_FORMAT,
	"LABEL",	S_LABEL,
	"LEFTSTRING",	S_LEFTSTRING,
	"RIGHTSTRING",	S_RIGHTSTRING,
	"GET",	S_GET,
	"PUT",	S_PUT,
	"MERGE",	S_MERGE,
	"LET",	S_LET,
	"WRITE",	S_WRITE,
	"TBL",	S_TBL,
	"COPY",	S_COPY,
	"SHOW",	S_SHOW,
	"ERASE",	S_ERASE,
	"FILL",	S_FILL,
	"GOTO",	S_GOTO,
	"DEFINE",	S_DEFINE,
	"UNDEFINE",	S_UNDEFINE,
	"VALUE",	S_VALUE,
	"MDIR",	S_MDIR,
	"HIDE",	S_HIDE,
	"SET",	S_SET,

Added utils/eres.sed.





>
>
1
2
/%token.*K_/!d
/%token.*K_\(.*\)/s//	"\1",	K_\1,/

Added utils/fromcsv.py.









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/python
#
# fromcsv.py
#	Convert CSV into sc input file
#
import sys, csv, string
uctab = string.ascii_uppercase
w = sys.stdout.write

row = col = 0
if __name__ == "__main__":
    for fn in sys.argv[1:]:
	f = open(fn, "r")
	for tup in csv.reader(f):
	    for col,s in enumerate(tup):
		w('leftstring %s%s = "%s"\n' %
		    (uctab[col], row, s))
	    row += 1
	f.close()
sys.exit(0)

Added utils/sres.sed.





>
>
1
2
/%token.*S_/!d
/%token.*S_\(.*\)/s//	"\1",	S_\1,/

Added xmalloc.c.



























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
 * A safer saner malloc, for careless programmers
 * $Revision: 1.1 $
 */

#include <stdio.h>
#include <curses.h>

extern char *malloc();

#ifdef SYSV3
extern void free();
extern void exit();
#endif

char *
xmalloc(n)
unsigned n;
{
register char *ptr;

if ((ptr = malloc(n + sizeof(double))) == NULL)
    fatal("xmalloc: no memory");
*((int *) ptr) = 12345;		/* magic number */
return(ptr + sizeof(double));
}

xfree(p)
char *p;
{
if (p == NULL)
    fatal("xfree: NULL");
p -= sizeof(double);
if (*((int *) p) != 12345)
    fatal("xfree: storage not malloc'ed");
free(p);
}

fatal(str)
char *str;
{
    deraw();
    (void) fprintf(stderr,"%s\n", str);
    exit(1);
}

Added y_tab.h.











































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#define STRING 257
#define NUMBER 258
#define FNUMBER 259
#define RANGE 260
#define VAR 261
#define WORD 262
#define COL 263
#define S_FORMAT 264
#define S_LABEL 265
#define S_LEFTSTRING 266
#define S_RIGHTSTRING 267
#define S_GET 268
#define S_PUT 269
#define S_MERGE 270
#define S_LET 271
#define S_WRITE 272
#define S_TBL 273
#define S_COPY 274
#define S_SHOW 275
#define S_ERASE 276
#define S_FILL 277
#define S_GOTO 278
#define S_DEFINE 279
#define S_UNDEFINE 280
#define S_VALUE 281
#define S_MDIR 282
#define S_HIDE 283
#define S_SET 284
#define K_FIXED 285
#define K_SUM 286
#define K_PROD 287
#define K_AVG 288
#define K_STDDEV 289
#define K_ACOS 290
#define K_ASIN 291
#define K_ATAN 292
#define K_ATAN2 293
#define K_CEIL 294
#define K_COS 295
#define K_EXP 296
#define K_FABS 297
#define K_FLOOR 298
#define K_HYPOT 299
#define K_LN 300
#define K_LOG 301
#define K_PI 302
#define K_POW 303
#define K_SIN 304
#define K_SQRT 305
#define K_TAN 306
#define K_DTR 307
#define K_RTD 308
#define K_MAX 309
#define K_MIN 310
#define K_RND 311
#define K_PV 312
#define K_FV 313
#define K_PMT 314
#define K_HOUR 315
#define K_MINUTE 316
#define K_SECOND 317
#define K_MONTH 318
#define K_DAY 319
#define K_YEAR 320
#define K_NOW 321
#define K_DATE 322
#define K_FMT 323
#define K_SUBSTR 324
#define K_STON 325
#define K_EQS 326
#define K_EXT 327
#define K_NVAL 328
#define K_SVAL 329
#define K_LOOKUP 330
#define K_STLOOKUP 331
#define K_INDEX 332
#define K_STINDEX 333
#define K_AUTO 334
#define K_AUTOCALC 335
#define K_BYROWS 336
#define K_BYCOLS 337
#define K_BYGRAPH 338
#define K_ITERATIONS 339
#define K_NUMERIC 340
#define K_PRESCALE 341
#define K_EXTFUN 342
#define K_CELLCUR 343
#define K_TOPROW 344
#define K_TBLSTYLE 345
#define K_TBL 346
#define K_LATEX 347
#define K_TEX 348
typedef union {
    int ival;
    double fval;
    struct ent_ptr ent;
    struct enode *enode;
    char *sval;
    struct range_s rval;
} YYSTYPE;
extern YYSTYPE yylval;