2
Copyright (c) 1994 - 2010, Lawrence Livermore National Security, LLC.
6
This file is part of Silo. For details, see silo.llnl.gov.
8
Redistribution and use in source and binary forms, with or without
9
modification, are permitted provided that the following conditions
12
* Redistributions of source code must retain the above copyright
13
notice, this list of conditions and the disclaimer below.
14
* Redistributions in binary form must reproduce the above copyright
15
notice, this list of conditions and the disclaimer (as noted
16
below) in the documentation and/or other materials provided with
18
* Neither the name of the LLNS/LLNL nor the names of its
19
contributors may be used to endorse or promote products derived
20
from this software without specific prior written permission.
22
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE
26
LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR
27
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
This work was produced at Lawrence Livermore National Laboratory under
36
Contract No. DE-AC52-07NA27344 with the DOE.
38
Neither the United States Government nor Lawrence Livermore National
39
Security, LLC nor any of their employees, makes any warranty, express
40
or implied, or assumes any liability or responsibility for the
41
accuracy, completeness, or usefulness of any information, apparatus,
42
product, or process disclosed, or represents that its use would not
43
infringe privately-owned rights.
45
Any reference herein to any specific commercial products, process, or
46
services by trade name, trademark, manufacturer or otherwise does not
47
necessarily constitute or imply its endorsement, recommendation, or
48
favoring by the United States Government or Lawrence Livermore
49
National Security, LLC. The views and opinions of authors expressed
50
herein do not necessarily state or reflect those of the United States
51
Government or Lawrence Livermore National Security, LLC, and shall not
52
be used for advertising or product endorsement purposes.
54
/*-------------------------------------------------------------------------
58
* Robb Matzke <matzke@viper.llnl.gov>
60
* Purpose: Builtin functions.
64
* Thomas Treadway, Thu Jun 8 16:56:35 PDT 2006
65
* Modified readline definitions to support new configure macro.
67
*-------------------------------------------------------------------------
69
#include <config.h> /*MeshTV configuration record*/
78
# ifndef FNM_FILE_NAME
79
# define FNM_FILE_NAME 0
82
#ifdef HAVE_READLINE_HISTORY
83
# if defined(HAVE_READLINE_HISTORY_H)
84
# include <readline/history.h>
85
# elif defined(HAVE_HISTORY_H)
87
# else /* !defined(HAVE_HISTORY_H) */
88
extern void add_history ();
89
extern int write_history ();
90
extern int read_history ();
91
# endif /* defined(HAVE_READLINE_HISTORY_H) */
93
#endif /* HAVE_READLINE_HISTORY */
98
/* Non-posix functions */
99
extern FILE *popen (const char *, const char *);
100
extern int pclose (FILE*);
102
/* Global variables. */
104
helptoc_t HelpFuncToc[25];
106
helptoc_t HelpVarToc[50];
108
helptoc_t HelpOpToc[25];
112
/*-------------------------------------------------------------------------
115
* Purpose: Creates a new array type.
117
* Return: Success: Ptr to new array type.
121
* Programmer: Robb Matzke
122
* matzke@viper.llnl.gov
127
* Robb Matzke, 30 Jul 1997
128
* Fixed a bug with the comma disappearing between string arguments.
130
*-------------------------------------------------------------------------
133
V_array (int argc, obj_t argv[]) {
140
out_errorn ("Array: wrong number of arguments");
145
for (i=0; i<argc-1; i++) {
146
if (argv[i] && C_NUM==argv[i]->pub.cls) {
147
sprintf (buf+at, "%s%d", at?", ":"", num_int (argv[i]));
148
at += strlen (buf+at);
150
} else if (argv[i] && (s=obj_name(argv[i]))) {
156
at += strlen (buf+at);
159
out_error ("Array: inappropriate dimension: ", argv[i]);
164
return obj_new (C_ARY, buf, obj_copy (argv[argc-1], SHALLOW));
168
/*-------------------------------------------------------------------------
171
* Purpose: Assigns an RVALUE to an LVALUE. If LVALUE is a symbol
172
* that has a variable value, then we assign RVALUE to that
173
* symbol. Otherwise, if LVALUE evaluates to an silo data
174
* object, we assign RVALUE to that SDO. Otherwise if LVALUE
175
* (unevaluated) is a symbol we assign RVALUE to that new
178
* Return: Success: The RVALUE
182
* Programmer: Robb Matzke
183
* robb@maya.nuance.mdn.com
188
* Robb Matzke, 19 Feb 1997
189
* Supports assignments to silo data objects.
191
*-------------------------------------------------------------------------
194
V_assign (int argc, obj_t argv[]) {
197
obj_t val=NIL, retval=NIL;
200
out_errorn ("Assign: wrong number of arguments");
204
if (!argv[0]) return NIL; /*error detected below*/
205
isa_symbol = (C_SYM == argv[0]->pub.cls);
208
* The LVALUE is a symbol with a variable value. Make the RVALUE the
209
* new variable value for that symbol.
211
if (isa_symbol && (val=sym_vboundp(argv[0]))) {
212
val = obj_dest (val);
213
sym_vbind (argv[0], obj_copy (argv[1], SHALLOW));
214
return obj_copy (argv[1], SHALLOW);
218
* Eval the LVALUE to see if it's a silo data object.
221
val = obj_eval (argv[0]);
223
if (val && C_SDO==val->pub.cls) {
224
retval = sdo_assign (val, argv[1]);
225
val = obj_dest (val);
228
val = obj_dest (val);
231
* The LVALUE is a symbol that doesn't evaluate to a silo data object.
232
* Assign the RVALUE as the variable value of the symbol.
235
sym_vbind (argv[0], obj_copy (argv[1], SHALLOW));
236
return obj_copy (argv[1], SHALLOW);
240
* The LVALUE is not a symbol and doesn't evaluate to a silo
243
out_errorn ("Assign: left operand has no L-value");
248
/*-------------------------------------------------------------------------
251
* Purpose: Closes the files associated with the specified symbols.
253
* Return: Success: NIL
257
* Programmer: Robb Matzke
258
* robb@maya.nuance.mdn.com
263
* Robb Matzke, 3 Feb 1997
264
* Cleaned up error messages.
265
*-------------------------------------------------------------------------
268
V_close (int argc, obj_t argv[]) {
274
for (i=0; i<argc; i++) {
275
if (!argv[i] || C_SYM!=argv[i]->pub.cls) {
276
sprintf (ebuf, "close: inappropriate file symbol as arg-%d: ", i+1);
277
out_error (ebuf, argv[i]);
278
} else if (NIL==(file=sym_vboundp(argv[i])) || C_FILE!=file->pub.cls) {
279
out_errorn ("close: no file associated with %s", obj_name(argv[i]));
280
file = obj_dest (file);
282
file = obj_dest (file);
283
sym_vbind (argv[i], NIL);
290
/*-------------------------------------------------------------------------
293
* Purpose: Creates a new cons cell with a HEAD and TAIL.
295
* Return: Success: Ptr to new cons cell.
299
* Programmer: Robb Matzke
300
* matzke@viper.llnl.gov
305
*-------------------------------------------------------------------------
308
F_cons (obj_t head, obj_t tail) {
310
return obj_new (C_CONS, obj_copy(head, SHALLOW), obj_copy(tail, SHALLOW));
314
/*-------------------------------------------------------------------------
315
* Function: diff_lookup
317
* Purpose: Looks up a diff constant in the symbol table and returns
318
* its value. If the symbol has a value which is not a
319
* number or a value which is a negative number then the value
320
* is removed with a warning.
322
* Return: Success: Double value of the variable.
326
* Programmer: Robb Matzke
327
* robb@maya.nuance.mdn.com
332
* Mark C. Miller, Tue Nov 17 22:34:51 PST 2009
333
* Added logic to exclude epsilon diff params from requirement to not be
335
*-------------------------------------------------------------------------
338
diff_lookup (char *ascii_name) {
340
obj_t name=NIL, val=NIL;
342
double retval = -1.0;
345
name = obj_new (C_SYM, ascii_name);
346
if ((val=sym_vboundp(name))) {
347
if (!num_isfp(val)) {
348
sprintf (buf, "diff: value of `%s' is inappropriate: ", ascii_name);
349
out_error (buf, val);
350
sym_vbind (name, NIL);
351
} else if ((retval=num_fp(val))<0.0 && !strstr(ascii_name, "_eps")) {
352
out_errorn ("diff: value of `%s' is inappropriate: %d",
354
sym_vbind (name, NIL);
357
val = obj_dest (val);
359
name = obj_dest (name);
363
out_info ("diff: %-15s is disabled", ascii_name);
365
out_info ("diff: %-15s = %e", ascii_name, retval);
373
/*-------------------------------------------------------------------------
376
* Purpose: Determines whether two things differ.
378
* Return: Success: NIL
382
* Programmer: Robb Matzke
383
* robb@maya.nuance.mdn.com
387
* Robb Matzke, 2000-06-27
388
* Added the `two_column' diff option.
390
* Robb Matzke, 2000-06-28
391
* If more than two arguments are given then the argument
392
* list is split in half and operands from the first half are
393
* differenced against corresponding operands from the second
394
* half. If called with no arguments then the command-line
395
* database files are used as arguments.
397
* Robb Matzke, 2000-06-29
398
* The contents of the $exclude variable is parsed and cached
401
* Robb Matzke, 2000-07-05
402
* If invoked with one argument and that argument is a silo
403
* database object from file $1 then it will be differenced
404
* against an object of the same name from file $2.
406
* Robb Matzke, 2000-07-10
407
* Fixed a memory corruption bug when called with no
408
* arguments and no files opened on the command-line
410
* Mark C. Miller, Wed Nov 11 22:18:17 PST 2009
411
* Added suppot for alternate relative diff option using
414
* Mark C. Miller, Mon Jan 11 16:21:21 PST 2010
415
* Added support for long long diffing params.
416
*-------------------------------------------------------------------------
419
V_diff (int argc, obj_t argv[])
422
int old_rtmargin = OUT_STDOUT->rtmargin;
423
obj_t opands[1024], head=NIL, value=NIL, symbol=NIL, word=NIL;
426
memset(&DiffOpt, 0, sizeof DiffOpt);
429
/* When invoked with no arguments use the list of command-line
430
* files as arguments. */
431
for (nopands=0; nopands<NELMTS(opands); nopands++) {
434
sprintf(tmp, "$%d", nopands+1);
435
symbol = obj_new(C_SYM, tmp);
436
opands[nopands] = sym_vboundp(symbol);
437
symbol = obj_dest(symbol);
438
if (!opands[nopands] || C_FILE!=opands[nopands]->pub.cls) {
439
/*we reached the last file or something isn't a file*/
440
opands[nopands] = obj_dest(opands[nopands]);
444
} else if (1==argc) {
445
/* When invoked with one argument which is a silo object from the
446
* file represented by `$1', the second argument is the silo
447
* object of the same name from file `$2'. */
448
obj_t my_file=NIL, file_1=NIL, file_2=NIL;
450
if (!argv[0] || C_SDO!=argv[0]->pub.cls) {
451
out_errorn("diff: single-argument must be a silo object");
454
my_file = sdo_file(argv[0]);
456
symbol = obj_new(C_SYM, "$1");
457
file_1 = sym_vboundp(symbol);
458
symbol = obj_dest(symbol);
459
if (!file_1 || C_FILE!=file_1->pub.cls) {
460
out_errorn("diff: single-argument must be from file $1");
461
my_file = obj_dest(my_file);
462
file_1 = obj_dest(file_1);
465
if (strcmp(obj_name(my_file), obj_name(file_1))) {
466
out_errorn("diff: single-argument must be from file $1");
467
my_file = obj_dest(my_file);
468
file_1 = obj_dest(file_1);
471
my_file = obj_dest(my_file);
472
file_1 = obj_dest(file_1);
475
symbol = obj_new(C_SYM, "$2");
476
file_2 = sym_vboundp(symbol);
477
symbol = obj_dest(symbol);
478
if (!file_2 || C_FILE!=file_2->pub.cls) {
479
out_errorn("diff: file $2 is not defined");
480
file_2 = obj_dest(file_2);
484
symbol = obj_new(C_SYM, obj_name(argv[0]));
485
opands[nopands++] = obj_copy(argv[0], SHALLOW);
486
opands[nopands++] = obj_deref(file_2, 1, &symbol);
487
symbol = obj_dest(symbol);
490
for (nopands=0; nopands<argc && nopands<NELMTS(opands); nopands++) {
491
opands[nopands] = obj_copy(argv[nopands], SHALLOW);
495
/* The number of operands had better be even */
497
out_errorn("diff requires an even number of arguments or "
498
"command-line database files");
502
out_errorn("nothing to difference");
506
/* Parse and cache $diff value */
507
symbol = obj_new(C_SYM, "$diff");
508
head = sym_vboundp(symbol);
509
symbol = obj_dest(symbol);
510
if (head && C_CONS!=head->pub.cls) {
511
head = obj_new(C_CONS, obj_copy(head, SHALLOW), NIL);
513
for (value=head; value; value=cons_tail(value)) {
514
if (C_CONS!=value->pub.cls) {
515
out_errorn("diff: invalid value for $diff");
518
word = cons_head(value);
519
if (C_SYM==word->pub.cls) {
520
if (!strcmp(obj_name(word), "all")) {
521
DiffOpt.report = DIFF_REP_ALL;
522
} else if (!strcmp(obj_name(word), "detail")) {
523
DiffOpt.report = DIFF_REP_ALL;
524
} else if (!strcmp(obj_name(word), "detailed")) {
525
DiffOpt.report = DIFF_REP_ALL;
526
} else if (!strcmp(obj_name(word), "brief")) {
527
DiffOpt.report = DIFF_REP_BRIEF;
528
} else if (!strcmp(obj_name(word), "sum")) {
529
DiffOpt.report = DIFF_REP_SUMMARY;
530
} else if (!strcmp(obj_name(word), "summary")) {
531
DiffOpt.report = DIFF_REP_SUMMARY;
532
} else if (!strcmp(obj_name(word), "summarize")) {
533
DiffOpt.report = DIFF_REP_SUMMARY;
534
} else if (!strcmp(obj_name(word), "ignore_additions")) {
535
DiffOpt.ignore_adds = true;
536
} else if (!strcmp(obj_name(word), "ignore_deletions")) {
537
DiffOpt.ignore_dels = true;
538
} else if (!strcmp(obj_name(word), "two_column")) {
539
DiffOpt.two_column = true;
541
out_errorn("word `%s' of $diff isn't recognized (ignored)",
545
out_errorn("diff: invalid value for $diff");
549
head = obj_dest(head);
551
/* Parse and cache $exclude values */
552
symbol = obj_new(C_SYM, "$exclude");
553
head = sym_vboundp(symbol);
554
symbol = obj_dest(symbol);
555
if (head && C_CONS!=head->pub.cls) {
556
head = obj_new(C_CONS, obj_copy(head, SHALLOW), NIL);
558
for (value=head; value; value=cons_tail(value)) {
559
if (C_CONS!=value->pub.cls) {
560
out_errorn("diff: invalid value for $exclude");
563
if (DiffOpt.exclude.nused>=NELMTS(DiffOpt.exclude.value)) {
564
out_errorn("diff: too many exclusions (limit %lu)",
565
(unsigned long)NELMTS(DiffOpt.exclude.value));
568
word = cons_head(value);
569
if (C_STR==word->pub.cls) {
570
i = DiffOpt.exclude.nused++;
571
DiffOpt.exclude.value[i] = safe_strdup(obj_name(word));
573
if (strpbrk(DiffOpt.exclude.value[i], "*?[]")) {
574
out_errorn("diff: $exclude = \"%s\" contains wildcards but "
575
"your C library doesn't have the `fnmatch' "
576
"function. Names will be matched literally.",
577
DiffOpt.exclude.value[i]);
581
out_errorn("diff: $exclude values should be strings");
585
head = obj_dest(head);
587
/* Cache tolerances */
588
DiffOpt.c_abs = diff_lookup("$diff_int8_abs");
589
DiffOpt.c_rel = diff_lookup("$diff_int8_rel");
590
DiffOpt.c_eps = diff_lookup("$diff_int8_eps");
591
DiffOpt.s_abs = diff_lookup("$diff_short_abs");
592
DiffOpt.s_rel = diff_lookup("$diff_short_rel");
593
DiffOpt.s_eps = diff_lookup("$diff_short_eps");
594
DiffOpt.i_abs = diff_lookup("$diff_int_abs");
595
DiffOpt.i_rel = diff_lookup("$diff_int_rel");
596
DiffOpt.i_eps = diff_lookup("$diff_int_eps");
597
DiffOpt.l_abs = diff_lookup("$diff_long_abs");
598
DiffOpt.l_rel = diff_lookup("$diff_long_rel");
599
DiffOpt.l_eps = diff_lookup("$diff_long_eps");
600
DiffOpt.f_abs = diff_lookup("$diff_float_abs");
601
DiffOpt.f_rel = diff_lookup("$diff_float_rel");
602
DiffOpt.f_eps = diff_lookup("$diff_float_eps");
603
DiffOpt.d_abs = diff_lookup("$diff_double_abs");
604
DiffOpt.d_rel = diff_lookup("$diff_double_rel");
605
DiffOpt.d_eps = diff_lookup("$diff_double_eps");
606
DiffOpt.ll_abs = diff_lookup("$diff_llong_abs");
607
DiffOpt.ll_rel = diff_lookup("$diff_llong_rel");
608
DiffOpt.ll_eps = diff_lookup("$diff_llong_eps");
611
for (i=0; i<nopands/2; i++) {
612
char header[8192], a_buf[32], b_buf[32];
613
const char *a_name, *b_name;
615
/* Print a table header for each pair of arguments */
616
if (NULL==(a_name=obj_name(opands[i]))) {
617
sprintf(a_buf, "Argument %d", i+1);
620
if (NULL==(b_name=obj_name(opands[nopands/2+i]))) {
621
sprintf(b_buf, "Argument %d", nopands/2+i+1);
625
/* Skip a line between each pair of arguments */
626
strcpy(header, i?"\n":"");
628
/* Choose a header line appropriate for the output style */
629
if (DIFF_REP_ALL==DiffOpt.report && DiffOpt.two_column) {
630
sprintf(header+strlen(header), "%-*s%-*s%*s%s\n",
631
OUT_LTMAR, "Object", OUT_COL2-OUT_LTMAR, a_name,
632
(int)strlen(DIFF_SEPARATOR), "", b_name);
633
OUT_STDOUT->rtmargin = 0; /*don't split long lines*/
635
sprintf(header+strlen(header), "Differences between %s and %s\n",
639
/* Put a line below the header */
640
for (j=0; j<OUT_NCOLS-2; j++) strcat(header, "-");
641
out_header(OUT_STDOUT, header);
643
/* The difference... */
644
status = obj_diff(opands[i], opands[nopands/2+i]);
645
if (!out_brokenpipe(OUT_STDOUT)) {
646
switch (DiffOpt.report) {
649
out_line(OUT_STDOUT, "***************");
650
obj_print(opands[i], OUT_STDOUT);
651
out_line(OUT_STDOUT, "---------------");
652
obj_print(opands[nopands/2+i], OUT_STDOUT);
653
out_line(OUT_STDOUT, "***************");
658
out_puts(OUT_STDOUT, "different value(s)");
662
case DIFF_REP_SUMMARY:
664
out_line(OUT_STDOUT, "objects differ");
672
/* Restore output margins and cancel table headers*/
673
OUT_STDOUT->rtmargin = old_rtmargin;
674
out_header(OUT_STDOUT, NULL);
676
/* Free temp expressions */
681
for (i=0; i<nopands; i++) obj_dest(opands[i]);
684
for (i=0; i<DiffOpt.exclude.nused; i++) {
685
if (DiffOpt.exclude.value[i]) {
686
free(DiffOpt.exclude.value[i]);
687
DiffOpt.exclude.value[i] = NULL;
695
/*-------------------------------------------------------------------------
698
* Purpose: A binary operator. The left operand should be a file
699
* and the right operand should be an object name within
702
* Or the left operand should be memory with a structure
703
* type and the right operand should be a field name within
706
* Or the left operand should be memory with an array type
707
* and the right operand(s) should be indices or ranges
710
* Return: Success: Ptr to a SILO database object.
714
* Programmer: Robb Matzke
715
* matzke@viper.llnl.gov
720
* Robb Matzke, 4 Feb 1997
721
* More than one argument is allowed.
723
*-------------------------------------------------------------------------
726
V_dot (int argc, obj_t argv[]) {
731
retval = obj_deref(argv[0], argc-1, argv+1);
733
out_error ("Dot: inappropriate left operand: ", argv[0]);
740
/*-------------------------------------------------------------------------
743
* Purpose: Exit the program. If a numeric argument is specified then
744
* we exit with that value.
746
* Return: Success: Does not return
750
* Programmer: Robb Matzke
751
* matzke@viper.llnl.gov
756
* Robb Matzke, 3 Feb 1997
757
* If an argument is supplied then it must be an integer.
759
* Robb Matzke, 10 Feb 1997
760
* History is saved in a history file.
762
* Sean Ahern, Fri Feb 28 14:12:58 PST 1997
763
* Added a check for the readline library.
765
* Thomas R. Treadway, Tue Jun 27 13:59:21 PDT 2006
766
* Added HAVE_STRERROR wrapper
768
* Thomas R. Treadway, Thu Mar 1 09:37:31 PST 2007
769
* Corrected write history logic
771
*-------------------------------------------------------------------------
774
V_exit (int argc, obj_t argv[]) {
776
#if defined(HAVE_READLINE_HISTORY_H) && defined(HISTORY_FILE) && defined(HAVE_READLINE_HISTORY)
777
if (HistoryFile[0] && write_history (HistoryFile))
782
out_errorn ("command history not saved in %s (%s)",
783
HistoryFile, strerror(errno));
785
out_errorn ("command history not saved in %s (errno=%d)",
796
if (!num_int(argv[0])) {
797
out_errorn ("exit: arg-1 is not an integer");
800
exit (num_int(argv[0]));
803
out_errorn ("exit: wrong number of arguments");
808
/*-------------------------------------------------------------------------
811
* Purpose: Bind a function to a name.
815
* Programmer: Robb Matzke
816
* matzke@viper.llnl.gov
821
*-------------------------------------------------------------------------
824
F_fbind (obj_t self, obj_t func) {
826
assert (self && C_SYM==self->pub.cls);
827
sym_fbind (self, obj_copy(func, SHALLOW));
831
/*-------------------------------------------------------------------------
834
* Purpose: Opens a SILO file but does not associate that file with
835
* a symbol. Thus, as soon as all references to this file
836
* object dissappear, the file is closed.
838
* Return: Success: Ptr to a silo file object.
842
* Programmer: Robb Matzke
843
* matzke@viper.llnl.gov
848
* Robb Matzke, 7 Feb 1997
849
* Changed the name of this function from F_open to V_file.
851
* Robb Matzke, 2 Apr 1997
852
* If `$rdonly' is true then the file is open for reading only.
854
*-------------------------------------------------------------------------
857
V_file (int argc, obj_t argv[]) {
859
obj_t retval=NIL, filename=NIL;
861
int rdonly = sym_bi_true("rdonly");
864
out_errorn ("file: wrong number of arguments");
870
out_errorn ("file: no file name given");
872
} else if (C_FILE==filename->pub.cls) {
873
retval = obj_copy (filename, SHALLOW); /*already opened*/
875
} else if (NULL==(fname=obj_name(filename))) {
876
out_errorn ("file: arg-1 is inappropriate");
878
} else if (NIL==(retval=obj_new (C_FILE, fname, rdonly))) {
879
#if 0 /*error message already printed*/
880
out_errorn ("file: could not open `%s'", fname);
887
/*-------------------------------------------------------------------------
888
* Function: F_flatten
890
* Purpose: Flattens a list so (a (b (c)) d) becomes (a b c d).
892
* Return: Success: A new list with shallow copies of the atoms.
896
* Programmer: Robb Matzke
897
* robb@maya.nuance.mdn.com
902
*-------------------------------------------------------------------------
905
F_flatten (obj_t lst) {
911
if (!lst || C_CONS!=lst->pub.cls) {
912
return obj_copy (lst, SHALLOW); /*nothing to flatten*/
916
* Create a stack of all the atoms.
918
for (/*void*/; lst; lst=cons_tail(lst)) {
919
obj_t hd = cons_head (lst);
924
opstack = obj_new (C_CONS, NIL, opstack);
926
} else if (C_CONS==hd->pub.cls) {
928
* Head is a list. Flatten it and then add those elements
931
obj_t flattened = F_flatten (hd);
932
for (ptr=flattened; ptr; ptr=cons_tail(ptr)) {
933
opstack = obj_new (C_CONS, F_head(ptr), opstack);
935
flattened = obj_dest (flattened);
939
* Add a copy of the head to the opstack.
941
opstack = obj_new (C_CONS, obj_copy(hd, SHALLOW), opstack);
946
* Return the reversal of the stack.
948
retval = F_reverse (opstack);
949
opstack = obj_dest (opstack);
954
/*-------------------------------------------------------------------------
957
* Purpose: Returns the head of a list.
959
* Return: Success: Ptr to the head.
963
* Programmer: Robb Matzke
964
* matzke@viper.llnl.gov
969
*-------------------------------------------------------------------------
974
if (!lst) return NIL;
975
if (C_CONS!=lst->pub.cls) return NIL;
977
return obj_copy (cons_head(lst), SHALLOW);
980
/*---------------------------------------------------------------------------
981
* Purpose: Callback for help apropos function.
983
* Programmer: Robb Matzke
984
* Wednesday, June 7, 2000
987
*---------------------------------------------------------------------------
990
help_apropos(obj_t sym, void *cdata)
992
const char *s = (const char*)cdata;
993
obj_t doc = sym_dboundp(sym);
996
if (doc && C_STR==doc->pub.cls) {
997
const char *docstr = obj_name(doc);
998
if (strstr(obj_name(sym), s) || strstr(docstr, s)) {
1000
sprintf(buf, "help %s", obj_name(sym));
1001
out_line(OUT_STDOUT, buf);
1010
/*-------------------------------------------------------------------------
1013
* Purpose: Offers help.
1015
* Return: Success: NIL
1019
* Programmer: Robb Matzke
1020
* robb@maya.nuance.mdn.com
1025
* Robb Matzke, 2000-06-02
1026
* Real users want a quick-and-dirty text-based help system a la
1027
* meshtvx. This command takes zero or one argument. When invoked
1028
* with zero arguments is prints a table of contents (TOC). When
1029
* invoked with a symbol name it prints the documentation string for
1030
* that symbol. When invoked with a string it searches all symbols
1031
* for the specified word and prints those that match. When invoked
1032
* with a symbol and a string it assigns the string as the
1033
* documentation for the symbol and returns null.
1034
*-------------------------------------------------------------------------
1037
V_help (int argc, obj_t argv[])
1040
obj_t doc=NIL, sym=NIL;
1041
static int ncalls=0;
1042
static helptoc_t toc[] = {
1043
{"help", "Help on the `help' function"},
1044
{"delta", "Changes since previous version"},
1045
{"faq", "Frequently asked questions"},
1046
{"run", "Browser execution and switches"},
1047
{"syntax", "Browser syntax"},
1048
{"functions", "Built-in functions"},
1049
{"operators", "Operators and precedence"},
1050
{"variables", "Predefined variables"},
1051
{"formats", "Data output formats"},
1052
{"paging", "Paging long output"},
1053
{"redirection", "Piping and output redirection"},
1054
{"interrupts", "Interrupting long-running commands"},
1055
{"traps", "Traps for the unwary"},
1056
{"$FOO", "Help for variable $FOO"},
1057
{"--FOO", "Help for command-line switch --FOO"},
1058
{"FOO", "Help for built-in function FOO"},
1059
{"\"opFOO\"", "Help for operator FOO"},
1060
{"\"FOO\"", "Help containing string \"FOO\""},
1064
/* Table of Contents */
1065
obj_t type = obj_new(C_STC, NULL, NULL);
1066
for (i=0; i<NELMTS(toc); i++) {
1068
sprintf(buf, "help %s", toc[i].name);
1069
stc_add(type, obj_new(C_PRIM, "string"),
1070
i*sizeof(*toc)+sizeof(char*), buf);
1072
doc = obj_new(C_SDO, NIL, NULL, toc, type, toc, type,
1074
sym = obj_new(C_SYM, "$toc");
1075
sym_dbind(sym, doc);
1080
type = obj_new(C_STC, NULL, NULL);
1081
for (i=0; i<NHelpFuncToc; i++) {
1083
sprintf(buf, "help %s", HelpFuncToc[i].name);
1084
stc_add(type, obj_new(C_PRIM, "string"),
1085
i*sizeof(helptoc_t)+sizeof(char*), buf);
1087
doc = obj_new(C_SDO, NIL, NULL, HelpFuncToc, type, HelpFuncToc, type,
1089
sym = obj_new(C_SYM, "functions");
1090
sym_dbind(sym, doc);
1095
type = obj_new(C_STC, NULL, NULL);
1096
for (i=0; i<NHelpOpToc; i++) {
1098
sprintf(buf, "help %s", HelpOpToc[i].name);
1099
stc_add(type, obj_new(C_PRIM, "string"),
1100
i*sizeof(helptoc_t)+sizeof(char*), buf);
1102
doc = obj_new(C_SDO, NIL, NULL, HelpOpToc, type, HelpOpToc, type,
1104
sym = obj_new(C_SYM, "operators");
1105
sym_dbind(sym, doc);
1110
type = obj_new(C_STC, NULL, NULL);
1111
for (i=0; i<NHelpVarToc; i++) {
1113
sprintf(buf, "help %s", HelpVarToc[i].name);
1114
stc_add(type, obj_new(C_PRIM, "string"),
1115
i*sizeof(helptoc_t)+sizeof(char*), buf);
1117
doc = obj_new(C_SDO, NIL, NULL, HelpVarToc, type, HelpVarToc, type,
1119
sym = obj_new(C_SYM, "variables");
1120
sym_dbind(sym, doc);
1125
/* Obtain the symbol */
1127
sym = obj_new(C_SYM, "$toc");
1128
} else if (!argv[0]) {
1129
out_errorn("help: first argument cannot be NIL");
1131
} else if (C_STR==argv[0]->pub.cls) {
1132
const char *s = obj_name(argv[0]);
1133
if (!strncmp("op", s, 2) && s[2]) {
1134
sym = obj_new(C_SYM, s);
1136
if (!sym_map(help_apropos, (void*)s)) {
1137
out_errorn("help: nothing appropriate");
1141
} else if (C_SYM==argv[0]->pub.cls) {
1144
out_errorn("help: wrong type for first argument");
1148
/* Set documentation string? */
1150
sym_dbind(argv[0], obj_copy(argv[1], SHALLOW));
1152
} else if (argc>2) {
1153
out_errorn("help: wrong number of arguments");
1157
/* Obtain documentation string */
1159
is_run = !strcmp("run", obj_name(sym));
1160
doc = sym_dboundp(sym);
1161
if (sym!=argv[0]) obj_dest(sym);
1164
/* `help run' is a special case */
1165
if (!doc && is_run) {
1170
/* Print documentation */
1172
/* Turn off string formating -- use out_putw() instead */
1173
obj_t fmt_string = obj_new(C_SYM, "$fmt_string");
1174
obj_t old_fmt = sym_vboundp(fmt_string);
1175
sym_bi_set("$fmt_string", NULL, NULL, NULL);
1177
/* Print documentation */
1178
obj_print(doc, OUT_STDOUT);
1181
/* Restore previous string format */
1182
sym_vbind(fmt_string, old_fmt);
1183
obj_dest(fmt_string);
1184
doc = obj_dest(doc);
1186
out_errorn("help: no documentation found.");
1191
/*---------------------------------------------------------------------------
1192
* Purpose: Cause subsequent input to come from the file named by the
1193
* argument. When that input source is exhausted then input
1194
* will begin to come from the original source again.
1198
* Programmer: Robb Matzke
1199
* Monday, July 10, 2000
1202
*---------------------------------------------------------------------------
1205
V_include(int argc, obj_t argv[])
1211
out_errorn("include: wrong number of arguments");
1214
if (NULL==(name=obj_name(argv[0]))) {
1215
out_errorn("include: no file name given");
1219
out_errorn("include: internal error -- no input source");
1222
if (NULL==(f=lex_open(name))) return NULL;
1223
lex_push(LEX_STDIN, f);
1228
/*-------------------------------------------------------------------------
1229
* Function: F_length
1231
* Purpose: Returns the number of elements in a list.
1233
* Return: Success: Length of LST
1235
* Failure: -1 if not a list, 0 if LST is NIL.
1237
* Programmer: Robb Matzke
1238
* matzke@viper.llnl.gov
1243
*-------------------------------------------------------------------------
1246
F_length (obj_t lst) {
1250
for (i=0; lst; lst=cons_tail(lst),i++) {
1251
if (C_CONS!=lst->pub.cls) return -1;
1257
/*-------------------------------------------------------------------------
1260
* Purpose: Lists the current working directory in the specified
1261
* file. If no file is specified then `$1' is assumed.
1263
* Return: Success: NIL
1267
* Programmer: Robb Matzke
1268
* matzke@viper.llnl.gov
1273
* Robb Matzke, 3 Feb 1997
1274
* Cleaned up error messages.
1276
* Robb Matzke, 6 Feb 1997
1277
* We list the objects ourselves instead of calling DBListDir because
1278
* it allows us to redirect and/or page the output. It also allows
1279
* us to make the output look more like the rest of the browser output.
1281
* Robb Matzke, 7 Feb 1997
1282
* Now takes any number of arguments. If the first argument is
1283
* a symbol with a file value, then use that file for the listing.
1284
* If the first argument is not a symbol, then evaluate it to get the
1285
* file to use for listing. Otherwise treat the first argument as
1286
* an item to list. All other arguments are items to list.
1288
* Robb Matzke, 25 Jul 1997
1289
* This function was indented to list the table of contents for the
1290
* current directory of a subset thereof. If object names and/or
1291
* wild cards are given, they apply to the names of the objects in the
1292
* current working directory. However, many people want to be able to
1293
* list the contents of a subdirectory by saying `ls dir1' where `dir1'
1294
* is a member of the current working directory. Therefore, after
1295
* wild-card expansion occurs, if the display list contains a single
1296
* object and that object is a directory, then we load the table of
1297
* contents from that directory and display it rather than the
1300
* Robb Matzke, 26 Aug 1997
1301
* Fixed a memory bug when the only argument is a directory name.
1303
* Lisa J. Roberts, Mon Nov 22 17:27:53 PST 1999
1304
* I changed strdup to safe_strdup.
1306
* Robb Matzke, 2000-05-17
1307
* If the argument is a directory name and that directory is empty
1308
* then the error message will be `ls: no table of contents' instead
1309
* of `ls: no matches'.
1311
* Robb Matzke, 2000-07-03
1312
* If the first argument is a list of files then perform the
1313
* operation once for each file of that list.
1314
*-------------------------------------------------------------------------
1317
V_list (int argc, obj_t argv[])
1319
obj_t fileobjs=NIL, ptr=NIL;
1322
if (argc>=1 && C_SYM==argv[0]->pub.cls) {
1323
/* Is the first symbol bound to a file or is it a special symbol
1324
* which evaluates to a file or list of files? */
1325
if ((fileobjs=sym_vboundp(argv[0]))) {
1326
if (C_FILE==fileobjs->pub.cls) {
1328
fileobjs = obj_new(C_CONS, fileobjs, NIL);
1330
fileobjs = obj_dest(fileobjs);
1332
} else if ((fileobjs=obj_eval(argv[0]))) {
1333
if (C_CONS==fileobjs->pub.cls) {
1336
fileobjs = obj_dest(fileobjs);
1340
} else if (argc>=1 && C_STR!=argv[0]->pub.cls) {
1341
/* The file is the result of evaluating the first expression. */
1342
fileobjs = obj_eval(argv[0]);
1343
if (!fileobjs) return NIL; /*error in eval*/
1344
if (C_FILE==fileobjs->pub.cls) {
1346
fileobjs = obj_new(C_CONS, fileobjs, NIL);
1348
out_errorn("ls: arg-1 does not evaluate to a file");
1353
/* Use the default file. */
1355
obj_t b1 = obj_new(C_SYM, "$1");
1356
fileobjs = sym_vboundp(b1);
1360
out_errorn("ls: no default open file (`$1' has no value)");
1363
fileobjs = obj_new(C_CONS, fileobjs, NIL);
1366
for (ptr=fileobjs; ptr; ptr=cons_tail(ptr)) {
1369
int i, nentries, width, old_type=(-1);
1371
int *selected=NULL, last_selected=-1;
1372
char buf[256], *needle, nselected=0;
1373
char cwd[1024], *subdir;
1375
/* Do we have a file? */
1376
obj_t fileobj = cons_head(ptr);
1377
if (!fileobj || C_FILE!=fileobj->pub.cls ||
1378
NULL==(file=file_file(fileobj))) {
1379
out_error("ls: inappropriate file: ", fileobj);
1383
/* Get the table of contents sorted first by object type and
1384
* then by object name. */
1385
toc = browser_DBGetToc(file, &nentries, sort_toc_by_type);
1386
if (!toc || 0==nentries) {
1387
out_errorn("ls: no table of contents");
1391
/* Prune the table of contents based on the arguments supplied. */
1392
selected = calloc(nentries, sizeof(int));
1393
if (first_arg==argc) {
1394
for (i=0; i<nentries; i++) selected[i] = true;
1396
for (argno=first_arg; argno<argc; argno++) {
1397
if (NULL==(needle=obj_name(argv[argno]))) {
1398
out_errorn("ls: arg-%d is not an object name", argno+1);
1400
#ifndef HAVE_FNMATCH
1401
if (strpbrk(needle, "*?[]")) {
1402
out_errorn("ls: arg-%d contains wildcards but your C "
1403
"library doesn't have the `fnmatch' "
1404
"function", argno+1);
1407
for (i=0; i<nentries; i++) {
1409
if (0==fnmatch(needle, toc[i].name,
1410
FNM_FILE_NAME|FNM_PERIOD)) {
1416
if (!strcmp(toc[i].name, needle)) {
1427
/* If the result is a single directory, then list the contents of
1428
* the directory instead of the directory name. */
1429
if (1==nselected && BROWSER_DB_DIR==toc[last_selected].type) {
1430
subdir = safe_strdup(toc[last_selected].name);
1431
for (i=0; i<nentries; i++) free(toc[i].name);
1433
if (DBGetDir(file, cwd)<0) return NIL;
1434
if (DBSetDir(file, subdir)<0) return NIL;
1435
toc = browser_DBGetToc(file, &nentries, sort_toc_by_type);
1436
if (DBSetDir(file, cwd)<0) return NIL;
1437
if (!toc || 0==nentries) {
1438
out_errorn("ls: no table of contents");
1441
out_info("Listing file: %s, directory: %s:",
1442
obj_name(fileobj), subdir);
1447
/* select all entries of that directory for display */
1449
selected = calloc(nentries, sizeof(int));
1450
for (i=0; i<nentries; i++) selected[i] = true;
1452
out_info("Listing from file %s", obj_name(fileobj));
1455
/* Find the widest entry and if any entries were even selected. */
1457
for (i=0; i<nentries; i++) {
1458
if (selected[i]) width = MAX(width, strlen(toc[i].name));
1461
out_errorn("ls: no matches");
1464
/* Print the objects grouped by object type. Each group of objects
1465
* has a prefix only on the first line. */
1467
for (i=nprint=0; i<nentries && !out_brokenpipe(OUT_STDOUT); i++) {
1468
if (!selected[i]) continue;
1469
if (toc[i].type!=old_type) {
1474
sprintf(buf, "%s(s)", ObjTypeName[toc[i].type]);
1475
out_push(OUT_STDOUT, buf);
1477
out_printf(OUT_STDOUT, " %-*s", width, toc[i].name);
1478
if (toc[i].type!=old_type) {
1479
out_pop(OUT_STDOUT);
1480
old_type = toc[i].type;
1488
for (i=0; i<nentries; i++) free(toc[i].name);
1500
/*-------------------------------------------------------------------------
1501
* Function: V_make_list
1503
* Purpose: Returns a list of the arguments. The list is not the
1504
* same list as the original arguments since the arguments
1505
* have been evaluated.
1507
* Return: Success: Ptr to a new list with shallow copies of
1508
* the caller-evaluated arguments
1512
* Programmer: Robb Matzke
1513
* robb@maya.nuance.mdn.com
1518
*-------------------------------------------------------------------------
1521
V_make_list (int argc, obj_t argv[]) {
1523
obj_t opstack=NIL, retval=NIL;
1526
for (i=0; i<argc; i++) {
1527
opstack = obj_new (C_CONS,
1528
obj_copy (argv[i], SHALLOW),
1531
retval = F_reverse (opstack);
1532
opstack = obj_dest (opstack);
1537
/*-------------------------------------------------------------------------
1538
* Function: V_noprint
1540
* Purpose: Returns NIL. Used to suppress the output of a non-nil
1543
* Return: Success: NIL
1547
* Programmer: Robb Matzke
1548
* robb@maya.nuance.mdn.com
1553
*-------------------------------------------------------------------------
1557
V_noprint (int argc, obj_t argv[]) {
1563
/*-------------------------------------------------------------------------
1566
* Purpose: Sets the current file to be the named SILO file. The
1567
* current file is called `$1'. If an even number of
1568
* arguments are present then the first argument of each pair
1569
* is the name of a SILO file and the second argument is the
1570
* name of the variable that will hold that file.
1572
* Return: Success: NIL
1576
* Programmer: Robb Matzke
1577
* matzke@viper.llnl.gov
1582
* Robb Matzke, 3 Feb 1997
1583
* Changed the name displayed in error messages to `open' since
1584
* this function is usually invoked with the `open' command.
1586
* Robb Matzke, 6 Feb 1997
1587
* The previous file is closed even if the new file can't be opened.
1589
* Robb Matzke, 7 Feb 1997
1590
* Takes just one or two arguments. Changed the name of this function
1591
* from V_with to V_open.
1593
*-------------------------------------------------------------------------
1596
V_open (int argc, obj_t argv[]) {
1598
obj_t file=NIL, filename=NIL, var=NIL;
1601
* Get the variable name
1604
filename = obj_copy (argv[0], SHALLOW);
1605
var = obj_copy (argv[1], SHALLOW);
1606
} else if (1==argc) {
1607
filename = obj_copy (argv[0], SHALLOW);
1608
var = obj_new (C_SYM, "$1");
1610
out_errorn ("open: wrong number of arguments");
1614
if (C_SYM!=var->pub.cls) {
1615
out_errorn ("open: arg-2 should be a symbol");
1623
char *ascii_name = obj_name (filename);
1624
out_info ("opening `%s' as %s",
1625
ascii_name?ascii_name:"***NO NAME***", obj_name (var));
1627
file = V_file (1, &filename);
1629
sym_vbind (var, NIL);
1634
* Assign the file to the variable.
1636
sym_vbind (var, file);
1637
var = obj_dest (var);
1638
file = NIL ; /*do not destroy file*/
1642
if (file ) file = obj_dest (file );
1643
if (var ) var = obj_dest (var );
1644
if (filename) filename = obj_dest (filename);
1649
/*-------------------------------------------------------------------------
1652
* Purpose: Evaluates and prints the first argument with standard output
1653
* redirected to the shell command specified by the second
1656
* Return: Success: NIL
1660
* Programmer: Robb Matzke
1661
* robb@maya.nuance.mdn.com
1666
* Robb Matzke, 3 Feb 1997
1667
* Cleaned up error messages.
1669
*-------------------------------------------------------------------------
1672
V_pipe (int argc, obj_t argv[]) {
1676
char *command, *fmode;
1682
out_errorn ("Pipe: wrong number of arguments");
1685
if (NULL==(command=obj_name(argv[1]))) {
1686
out_error ("Pipe: arg-2 (command) is inappropriate: ", argv[1]);
1689
if (NULL==(fmode=obj_name(argv[2]))) {
1690
out_error ("Pipe: arg-3 (mode) is inappropriate: ", argv[2]);
1693
if (NULL==(f=popen(command, fmode))) {
1694
out_errorn ("Pipe: could not run: %s", command);
1699
* Point OUT_STDOUT at the pipe.
1703
saved = *OUT_STDOUT;
1704
out_reset (OUT_STDOUT);
1706
OUT_STDOUT->paged = false;
1709
* Evaluate the first argument.
1711
out = obj_eval (argv[0]);
1712
if (out || Verbosity>=2) {
1713
obj_print (out, OUT_STDOUT);
1714
out_nl (OUT_STDOUT);
1716
out = obj_dest (out);
1719
* Point OUT_STDOUT at the original stream.
1721
*OUT_STDOUT = saved;
1726
status = pclose (f);
1727
if (WIFEXITED(status)) {
1728
if (WEXITSTATUS(status)) {
1729
out_errorn ("Pipe: command failed with exit status: %d",
1730
WEXITSTATUS(status));
1732
} else if (WIFSIGNALED(status)) {
1733
out_errorn ("Pipe: command received signal %d", WTERMSIG(status));
1740
/*-------------------------------------------------------------------------
1741
* Function: V_pointer
1743
* Purpose: Creates a pointer to the first argument.
1745
* Return: Success: Pointer type object.
1749
* Programmer: Robb Matzke
1750
* robb@callisto.nuance.mdn.com
1755
*-------------------------------------------------------------------------
1758
V_pointer (int argc, obj_t argv[]) {
1761
out_errorn ("pointer: wrong number of arguments");
1764
return obj_new (C_PTR, obj_copy (argv[0], SHALLOW));
1768
/*-------------------------------------------------------------------------
1769
* Function: V_primitive
1771
* Purpose: Given the name of a primitive type, return a new
1772
* primitive type object.
1774
* Return: Success: Primitive type object.
1778
* Programmer: Robb Matzke
1779
* matzke@viper.llnl.gov
1784
*-------------------------------------------------------------------------
1787
V_primitive (int argc, obj_t argv[]) {
1792
out_errorn ("primitive: wrong number of arguments");
1796
if (num_isint(argv[0])) {
1797
sprintf (buf, "%d", num_int(argv[0]));
1799
} else if (NULL==(s=obj_name(argv[0]))) {
1800
out_error ("primitive: type name is inappropriate: ", argv[0]);
1804
return obj_new (C_PRIM, s);
1808
/*-------------------------------------------------------------------------
1811
* Purpose: Prints each argument to standard output.
1813
* Return: Success: NIL
1817
* Programmer: Robb Matzke
1818
* matzke@viper.llnl.gov
1823
* Robb Matzke, 3 Feb 1997
1824
* NIL arguments are ignored. We do this because a command like `XXX'
1825
* is parsed as `print XXX' and if `XXX' is not an object we get an
1826
* error message and the `XXX' turns into a NIL pointer. Printing
1827
* `nil' would be redundant. However, this means that the command
1828
* `print nil' won't do anything!
1830
*-------------------------------------------------------------------------
1833
V_print (int argc, obj_t argv[]) {
1837
for (i=0; i<argc && !out_brokenpipe(OUT_STDOUT); i++) {
1839
obj_print (argv[i], OUT_STDOUT);
1840
out_nl (OUT_STDOUT);
1847
/*-------------------------------------------------------------------------
1850
* Purpose: Prints the current working directory of the specified file,
1851
* or `$1' if no file is specified. Actually, this function
1852
* doesn't really do anything but return the file, since the
1853
* print form of a file includes the current working
1856
* Return: Success: NIL
1860
* Programmer: Robb Matzke
1861
* robb@maya.nuance.mdn.com
1865
* Robb Matzke, 3 Feb 1997
1866
* Cleaned up error messages.
1868
* Robb Matzke, 2000-07-03
1869
* If invoked with a single argument which is a list of files
1870
* just return that list of files. This allows us to invoke
1871
* this command as `pwd $*' to show the current working
1872
* directories of all the command-line files.
1873
*-------------------------------------------------------------------------
1876
V_pwd (int argc, obj_t argv[])
1881
obj_t name = obj_new(C_SYM, "$1");
1882
retval = sym_vboundp(name);
1883
name = obj_dest(name);
1885
out_errorn("pwd: no default open file (`$1' has no value)");
1888
} else if (1==argc) {
1889
retval = obj_copy(argv[0], SHALLOW);
1891
out_errorn("pwd: wrong number of arguments");
1896
out_errorn("pwd: no file specified");
1898
} else if (C_CONS==retval->pub.cls) {
1900
for (ptr=retval; ptr; ptr=cons_tail(ptr)) {
1902
if (!f || C_FILE!=f->pub.cls) {
1903
out_errorn("pwd: arg is not a list of files");
1907
} else if (C_FILE!=retval->pub.cls) {
1908
out_errorn("pwd: argument is not a file");
1920
/*-------------------------------------------------------------------------
1923
* Purpose: Just returns a copy of the first argument. If there's more
1924
* than one argument then return a list of the arguments.
1926
* Return: Success: A copy of the first argument.
1930
* Programmer: Robb Matzke
1931
* robb@maya.nuance.mdn.com
1936
*-------------------------------------------------------------------------
1939
V_quote (int argc, obj_t argv[]) {
1941
if (argc<1) return NIL;
1942
if (1==argc) return obj_copy (argv[0], SHALLOW);
1943
return V_make_list (argc, argv);
1947
/*-------------------------------------------------------------------------
1948
* Function: V_redirect
1950
* Purpose: Redirects standard output to the specified file then evaluates
1951
* and prints the first argument. The file name is the
1954
* Return: Success: NIL
1958
* Programmer: Robb Matzke
1959
* matzke@viper.llnl.gov
1964
* Robb Matzke, 3 Feb 1997
1965
* Cleaned up error messages.
1967
* Thomas R. Treadway, Tue Jun 27 13:59:21 PDT 2006
1968
* Added HAVE_STRERROR wrapper
1970
*-------------------------------------------------------------------------
1973
V_redirect (int argc, obj_t argv[]) {
1978
char *fname=NULL, *fmode=NULL;
1981
out_errorn ("Redirect: wrong number of arguments");
1984
if (!argv[1] || NULL==(fname=obj_name(argv[1]))) {
1985
out_error ("Redirect: arg-2 (file name) is inappropriate", argv[1]);
1988
if (!argv[2] || NULL==(fmode=obj_name(argv[2]))) {
1989
out_error ("Redirect: arg-3 (mode) is inappropriate", argv[2]);
1992
if (NULL==(f=fopen(fname, fmode))) {
1993
#ifdef HAVE_STRERROR
1994
out_errorn ("Redirect: cannot open `%s' (%s)",
1995
fname, strerror(errno));
1997
out_errorn ("Redirect: cannot open `%s' (errno=%d)",
2006
saved = *OUT_STDOUT;
2007
out_reset (OUT_STDOUT);
2009
OUT_STDOUT->paged = false;
2011
out = obj_eval (argv[0]);
2012
if (out || Verbosity>=2) {
2013
obj_print (out, OUT_STDOUT);
2014
out_nl (OUT_STDOUT);
2016
out = obj_dest (out);
2018
*OUT_STDOUT = saved;
2025
/*-------------------------------------------------------------------------
2026
* Function: F_reverse
2028
* Purpose: Reverses list LST.
2030
* Return: Success: Ptr to a new list.
2034
* Programmer: Robb Matzke
2035
* matzke@viper.llnl.gov
2040
*-------------------------------------------------------------------------
2043
F_reverse (obj_t lst) {
2045
obj_t ret=NIL, b1, b2;
2047
if (!lst) return NIL;
2048
if (C_CONS!=lst->pub.cls) return obj_copy(lst, SHALLOW);
2050
for (/*void*/; lst; lst=cons_tail(lst)) {
2053
b2 = F_cons (b1, ret);
2062
/*-------------------------------------------------------------------------
2063
* Function: V_setcwd
2065
* Purpose: Sets the current working directory for a file (or for `$1'
2066
* if no file is specified).
2068
* Return: Success: The file.
2072
* Programmer: Robb Matzke
2073
* robb@maya.nuance.mdn.com
2077
* Robb Matzke, 3 Feb 1997
2078
* Cleaned up error messages.
2080
* Robb Matzke, 5 Feb 1997
2081
* The first argument is always the directory name. The second
2082
* argument is the optional file.
2084
* Robb Matzke, 2000-07-03
2085
* If the second argument is a list of files (instead of just a file)
2086
* then the current working directory is changed for all listed files
2087
* and the file list is returned. The return value is always the list
2088
* of files, even if something goes wrong (this allows the user to see
2089
* what the CWD is for each file).
2090
*-------------------------------------------------------------------------
2093
V_setcwd (int argc, obj_t argv[])
2095
obj_t files=NIL, cwd=NIL, ptr=NIL;
2101
obj_t name = obj_new (C_SYM, "$1");
2102
files = sym_vboundp (name);
2103
name = obj_dest (name);
2107
out_errorn ("cd: no default open file (`$1' has no value)");
2110
} else if (2==argc) {
2111
files = obj_copy (argv[1], SHALLOW);
2114
out_errorn ("cd: wrong number of arguments");
2118
/* Make sure `files' is a list of files and the directory name is some
2120
if (C_CONS!=files->pub.cls) {
2121
files = obj_new(C_CONS, files, NIL);
2123
if (!cwd || NULL==(dirname=obj_name(cwd))) {
2124
out_error ("cd: inappropriate directory name: ", cwd);
2128
/* Change directories for each file */
2129
for (ptr=files; ptr; ptr=cons_tail(ptr)) {
2130
obj_t f = cons_head(ptr);
2131
if (!f || C_FILE!=f->pub.cls || NULL==(dbfile=file_file(f))) {
2132
out_error("cd: inappropriate file: ", f);
2133
} else if (DBSetDir (dbfile, dirname)<0) {
2134
out_errorn ("cd: cannot set CWD to \"%s\" for file %s",
2135
dirname, obj_name(f));
2147
/*-------------------------------------------------------------------------
2150
* Purpose: Sets the symbols functional value (and removes an
2153
* Return: Success: NIL
2157
* Programmer: Robb Matzke
2158
* robb@maya.nuance.mdn.com
2163
* Robb Matzke, 3 Feb 1997
2164
* Cleaned up error messages.
2166
*-------------------------------------------------------------------------
2169
V_setf (int argc, obj_t argv[]) {
2172
out_errorn ("fsetf: wrong number of arguments");
2175
if (!argv[0] || C_SYM!=argv[0]->pub.cls) {
2176
out_error ("fsetf: arg-1 (symbol) is inappropriate: ", argv[0]);
2180
sym_fbind (argv[0], obj_copy(argv[1], SHALLOW));
2185
/*-------------------------------------------------------------------------
2186
* Function: V_struct
2188
* Purpose: Creates a structure. The first argument is the name
2189
* and the remaining arguments are offset and subtype pairs.
2191
* Return: Success: Ptr to a struct type object.
2195
* Programmer: Robb Matzke
2196
* matzke@viper.llnl.gov
2201
*-------------------------------------------------------------------------
2204
V_struct (int argc, obj_t argv[]) {
2207
int offset[32], i, argno;
2208
char *structname, *name[32];
2210
if (argc<4 || argc>NELMTS(sub)*3+1) {
2211
out_errorn ("struct: wrong number of arguments");
2215
memset (sub, 0, sizeof(sub));
2216
memset (offset, 0, sizeof(offset));
2217
memset (name, 0, sizeof(name));
2219
structname = obj_name (argv[0]);
2221
for (i=0,argno=1; i<NELMTS(sub) && argno+1<argc; i++,argno+=3) {
2225
if (!argv[argno] || C_NUM!=argv[argno]->pub.cls) {
2226
out_errorn ("struct: offset for component %d is not numeric", i+1);
2229
if ((offset[i]=num_int(argv[argno]))<0) {
2230
out_errorn ("struct: offset for component %d is out of range", i+1);
2237
if (NULL==(name[i]=obj_name(argv[argno+1]))) {
2238
out_errorn ("struct: component %d has no name", i+1);
2243
* The component type.
2245
sub[i] = argv[argno+2];
2247
out_errorn ("struct: component type %d is missing", i+1);
2252
return obj_new (C_STC, structname,
2253
obj_copy(sub[ 0], SHALLOW), offset[ 0], name[ 0],
2254
obj_copy(sub[ 1], SHALLOW), offset[ 1], name[ 1],
2255
obj_copy(sub[ 2], SHALLOW), offset[ 2], name[ 2],
2256
obj_copy(sub[ 3], SHALLOW), offset[ 3], name[ 3],
2257
obj_copy(sub[ 4], SHALLOW), offset[ 4], name[ 4],
2258
obj_copy(sub[ 5], SHALLOW), offset[ 5], name[ 5],
2259
obj_copy(sub[ 6], SHALLOW), offset[ 6], name[ 6],
2260
obj_copy(sub[ 7], SHALLOW), offset[ 7], name[ 7],
2261
obj_copy(sub[ 8], SHALLOW), offset[ 8], name[ 8],
2262
obj_copy(sub[ 9], SHALLOW), offset[ 9], name[ 9],
2263
obj_copy(sub[10], SHALLOW), offset[10], name[10],
2264
obj_copy(sub[11], SHALLOW), offset[11], name[11],
2265
obj_copy(sub[12], SHALLOW), offset[12], name[12],
2266
obj_copy(sub[13], SHALLOW), offset[13], name[13],
2267
obj_copy(sub[14], SHALLOW), offset[14], name[14],
2268
obj_copy(sub[15], SHALLOW), offset[15], name[15],
2269
obj_copy(sub[16], SHALLOW), offset[16], name[16],
2270
obj_copy(sub[17], SHALLOW), offset[17], name[17],
2271
obj_copy(sub[18], SHALLOW), offset[18], name[18],
2272
obj_copy(sub[19], SHALLOW), offset[19], name[19],
2273
obj_copy(sub[20], SHALLOW), offset[20], name[20],
2274
obj_copy(sub[21], SHALLOW), offset[21], name[21],
2275
obj_copy(sub[22], SHALLOW), offset[22], name[22],
2276
obj_copy(sub[23], SHALLOW), offset[23], name[23],
2277
obj_copy(sub[24], SHALLOW), offset[24], name[24],
2278
obj_copy(sub[25], SHALLOW), offset[25], name[25],
2279
obj_copy(sub[26], SHALLOW), offset[26], name[26],
2280
obj_copy(sub[27], SHALLOW), offset[27], name[27],
2281
obj_copy(sub[28], SHALLOW), offset[28], name[28],
2282
obj_copy(sub[29], SHALLOW), offset[29], name[29],
2283
obj_copy(sub[30], SHALLOW), offset[30], name[30],
2284
obj_copy(sub[31], SHALLOW), offset[31], name[31], NULL);
2288
/*-------------------------------------------------------------------------
2291
* Purpose: Returns the tail of a list.
2293
* Return: Success: Ptr to the tail
2297
* Programmer: Robb Matzke
2298
* matzke@viper.llnl.gov
2303
*-------------------------------------------------------------------------
2306
F_tail (obj_t lst) {
2308
if (!lst) return NIL;
2309
if (C_CONS!=lst->pub.cls) return NIL;
2311
return obj_copy (cons_tail(lst), SHALLOW);
2315
/*-------------------------------------------------------------------------
2316
* Function: V_typeof
2318
* Purpose: Prints the type of some object.
2320
* Return: Success: The type
2324
* Programmer: Robb Matzke
2325
* robb@maya.nuance.mdn.com
2330
* Robb Matzke, 3 Feb 1997
2331
* Works for all types of objects.
2333
*-------------------------------------------------------------------------
2336
V_typeof (int argc, obj_t argv[]) {
2342
out_errorn ("typeof: wrong number of arguments");
2349
} else if (C_SDO==argv[0]->pub.cls) {
2350
retval = obj_copy (sdo_typeof(argv[0]), SHALLOW);
2352
} else if (num_isint(argv[0])) {
2353
sprintf (buf, "%s_int", argv[0]->pub.cls->name);
2354
retval = obj_new (C_SYM, buf);
2356
} else if (num_isfp(argv[0])) {
2357
sprintf (buf, "%s_fp", argv[0]->pub.cls->name);
2358
retval = obj_new (C_SYM, buf);
2361
retval = obj_new (C_SYM, argv[0]->pub.cls->name);