1 /*
2  * $Id: silo.i,v 1.2 2006-12-17 18:22:03 dhmunro Exp $
3  * support for Silo files, a higher level binary format than PDB
4  */
5 /* Copyright (c) 2005, The Regents of the University of California.
6  * All rights reserved.
7  * This file is part of yorick (http://yorick.sourceforge.net).
8  * Read the accompanying LICENSE file for details.
9  */
10 
11 if (is_void(silo_openb)) silo_openb=is_void(basfix_openb)?openb:basfix_openb;
12 
silo_open(filename)13 func silo_open(filename)
14 /* DOCUMENT silo_open, filename
15          or silo= silo_open(filename)
16      open FILENAME for later use with silo_... functions
17 
18      There is a single current silo file, which is opened and set
19      by the first form.  The other silo_... functions normally
20      operate on this current file, but also accept a silo= keyword,
21      which is a list returned by the second calling sequence for
22      silo_open.
23 
24    SEE ALSO: silo_cd, silo_ls, silo_var, silo_close
25  */
26 {
27   f= silo_openb(filename);
28   vars= *get_vars(f)(1);
29   nvars= numberof(vars);
30   mask= strpart(vars,0:0)=="/";
31   list= where(mask);
32   ndirs= numberof(list);
33   grow, vars, vars(list)+"\377\377\377";  /* mark end of each dir */
34   grow, mask, array(-1, ndirs);
35   order= sort(vars);
36   vars= vars(order);
37   mask= mask(order);
38   invrs= order;
39   invrs(order)= indgen(nvars+ndirs);
40   list= invrs(list);
41   ends= invrs(nvars+1:nvars+ndirs);
42   lens= array(0,nvars+ndirs);
43   order= (mask<0)(psum);
44   lens(list)= ends - list - order(ends) + order(list);
45   list= where(mask>0);
46   lens= lens(list);
47   depth= mask(psum);
48   depth(list)-= 1;
49   list= where(mask>=0);
50   vars= vars(list);
51   depth= depth(list);
52   list= where(mask(list));
53   list= _lst(f, vars, depth, list, lens, "/");
54   if (am_subroutine()) {
55     extern silo_list;
56     silo_list= list;
57   } else {
58     return list;
59   }
60 }
61 
62 func silo_close(void, silo=)
63 /* DOCUMENT silo_close
64      close current silo file
65    SEE ALSO: silo_cd, silo_ls, silo_var, silo_open
66  */
67 {
68   if (is_void(silo)) {
69     close, _car(silo_list, 1, []);
70     silo_list= [];
71   } else {
72     close, _car(silo, 1, []);
73   }
74 }
75 
76 func silo_cd(dir, silo=)
77 /* DOCUMENT silo_cd, dirname
78      change current silo directory to DIRNAME, which may contain
79        .. or . constructs as a UNIX pathname
80      accepts silo= keyword to operate on a silo file other than the
81        current silo file
82    SEE ALSO: silo_ls, silo_var, silo_open, silo_close
83  */
84 {
85   list= is_void(silo)? silo_list : silo;
86   if (strpart(dir,0:0)=="/") dir= strpart(dir,1:-1);
87   if (strpart(dir,1:1)!="/") dir= _car(list,6) + dir;
88   dir= silo_simplify(dir) + "/";
89   if (dir=="//") dir= "/";
90   lst= where(dir==_car(list, 2)(_car(list, 4)));
91   if (!numberof(lst)) {
92     if (am_subroutine()) error, "no such directory as: "+dir;
93     return string(0);
94   }
95   _car, list, 6, dir;
96   return dir;
97 }
98 
99 func silo_var(var, silo=)
100 /* DOCUMENT var= silo_var(varname)
101      return silo variable VARNAME
102      accepts silo= keyword to operate on a silo file other than the
103        current silo file
104    SEE ALSO: silo_ls, silo_cd, silo_open, silo_close
105  */
106 {
107   list= is_void(silo)? silo_list : silo;
108   if (strpart(var,1:1)!="/") var= _car(list,6) + var;
109   return get_member(_car(list,1),silo_simplify(var));
110 }
111 
112 func silo_ls(name, &dirname, silo=)
113 /* DOCUMENT silo_ls
114          or silo_ls, dirname
115          or itemlist= silo_ls(dirname)
116          or itemlist= silo_ls(dirname, fulldirname)
117      list current silo directory or DIRNAME
118      if called as a function, returns a 1D array of strings beginning
119        with ".", and optionally returns FULLDIRNAME, which is the
120        full path name of the directory listed
121        - the individual items in the list do not include the
122          directory path
123        - subdirectory names end with "/", so you can find them
124          using strpart(itemlist,0:0)=="/"
125      accepts silo= keyword to operate on a silo file other than the
126        current silo file
127    SEE ALSO: silo_ls, silo_cd, silo_open, silo_close
128  */
129 {
130   list= is_void(silo)? silo_list : silo;
131   if (is_void(name)) name= ".";
132   if (strpart(name,0:0)=="/") name= strpart(name,1:-1);
133   if (strpart(name,1:1)!="/") name= _car(list,6) + name;
134   name= silo_simplify(name) + "/";
135   if (name=="//") name= "/";
136   local vars, lens;
137   eq_nocopy, vars, _car(list, 2);
138   eq_nocopy, depth, _car(list, 3);
139   eq_nocopy, lens, _car(list, 5);
140   eq_nocopy, list, _car(list, 4);
141   lst= where(name==vars(list));
142   if (!numberof(lst)) {
143     if (am_subroutine()) write, "no such directory as: "+name;
144     return [];
145   }
146   lst= lst(1);
147   lens= lens(lst);
148   list= list(lst);
149   vars= vars(list:list+lens);
150   depth= depth(list:list+lens);
151   dirname= vars(1);  /* full directory name */
152   vars(1)= ".";
153   if (numberof(vars)>1) {
154     depth(1)+= 1;
155     vars= vars(where(depth==depth(1)));
156     lens= strlen(dirname);
157     if (numberof(vars)>1) vars(2:0)= strpart(vars(2:0),lens+1:0);
158   }
159   if (am_subroutine()) write, format=" %s\n", vars;
160   return vars;
161 }
162 
silo_simplify(dir)163 func silo_simplify(dir)
164 {
165   if (strmatch(dir,"/.")) {
166     parts= array(string, 1000);
167     parse= strtok(dir, "/");
168     for (tok=parse(1),i=0 ; tok ; tok=parse(1)) {
169       if (tok!=".") {
170         if (tok=="..") i= max(0, i-1);
171         else parts(++i)= tok;
172       }
173       parse= strtok(parse(2), "/");
174     }
175     dir= i? "" : "/";
176     for (j=1 ; j<=i ; j++) dir+= "/"+parts(j);
177   }
178   return dir;
179 }
180