1implement Format; 2include "sys.m"; 3 sys: Sys; 4include "bufio.m"; 5 bufio: Bufio; 6 Iobuf: import bufio; 7include "sexprs.m"; 8 sexprs: Sexprs; 9 Sexp: import sexprs; 10include "format.m"; 11 12# possible addition? 13# se2spec(se: list of ref Sexp): (array of Fmtspec, string) 14 15init() 16{ 17 sys = load Sys Sys->PATH; 18 sexprs = load Sexprs Sexprs->PATH; 19 sexprs->init(); 20 bufio = load Bufio Bufio->PATH; 21} 22 23spec2se(spec: array of Fmtspec): list of ref Sexp 24{ 25 l: list of ref Sexp; 26 for(i := len spec - 1; i >= 0; i--){ 27 if((sp := spec[i]).fields != nil) 28 l = ref Sexp.List(ref Sexp.String(sp.name, nil) :: spec2se(sp.fields)) :: l; 29 else if(sp.name != nil) 30 l = ref Sexp.String(sp.name, nil) :: l; 31 } 32 return l; 33} 34 35spec2fmt(specs: array of Fmtspec): array of Fmt 36{ 37 if(specs == nil) 38 return nil; 39 f := array[len specs] of Fmt; 40 for(i := 0; i < len specs; i++){ 41 if(specs[i].name == nil) 42 f[i].kind = -1; 43 else 44 f[i] = (i, spec2fmt(specs[i].fields)); 45 } 46 return f; 47} 48 49 50se2fmt(spec: array of Fmtspec, se: ref Sexp): (array of Fmt, string) 51{ 52 if(!se.islist()) 53 return (nil, "format must be a list"); 54 return ses2fmt(spec, se.els()); 55} 56 57ses2fmt(spec: array of Fmtspec, els: list of ref Sexp): (array of Fmt, string) 58{ 59 a := array[len els] of Fmt; 60 for(i := 0; els != nil; els = tl els){ 61 name := (hd els).op(); 62 for(j := 0; j < len spec; j++) 63 if(spec[j].name == name) 64 break; 65 if(j == len spec) 66 return (nil, sys->sprint("format name %#q not found", name)); 67 sp := spec[j]; 68 if((hd els).islist() == 0) 69 a[i++] = Fmt(j, spec2fmt(sp.fields)); 70 else if(sp.fields == nil) 71 return (nil, sys->sprint("unexpected list %#q", name)); 72 else{ 73 (f, err) := ses2fmt(sp.fields, (hd els).args()); 74 if(f == nil) 75 return (nil, err); 76 a[i++] = Fmt(j, f); 77 } 78 } 79 return (a, nil); 80} 81 82rec2val(spec: array of Fmtspec, se: ref Sexprs->Sexp): (array of Fmtval, string) 83{ 84 if(se.islist() == 0) 85 return (nil, "expected list of fields; got "+se.text()); 86 els := se.els(); 87 if(len els > len spec) 88 return (nil, sys->sprint("too many fields found, expected %d, got %s", len spec, se.text())); 89 a := array[len spec] of Fmtval; 90 err: string; 91 for(i := 0; i < len spec; i++){ 92 f := spec[i]; 93 if(f.name == nil) 94 continue; 95 if(els == nil) 96 return (nil, sys->sprint("too few fields found, expected %d, got %s", len spec, se.text())); 97 el := hd els; 98 if(f.fields == nil) 99 a[i].val = el; 100 else{ 101 if(el.islist() == 0) 102 return (nil, "expected list of elements; got "+el.text()); 103 vl := el.els(); 104 a[i].recs = recs := array[len vl] of array of Fmtval; 105 for(j := 0; vl != nil; vl = tl vl){ 106 (recs[j++], err) = rec2val(spec[i].fields, hd vl); 107 if(err != nil) 108 return (nil, err); 109 } 110 } 111 els = tl els; 112 } 113 return (a, nil); 114} 115 116Fmtval.text(v: self Fmtval): string 117{ 118 return v.val.astext(); 119} 120 121Fmtfile.new(spec: array of Fmtspec): Fmtfile 122{ 123 return (spec, (ref Sexp.List(spec2se(spec))).pack()); 124} 125 126Fmtfile.open(f: self Fmtfile, name: string): ref Bufio->Iobuf 127{ 128 fd := sys->open(name, Sys->ORDWR); 129 if(fd == nil){ 130 sys->werrstr(sys->sprint("open failed: %r")); 131 return nil; 132 } 133 if(sys->write(fd, f.descr, len f.descr) == -1){ 134 sys->werrstr(sys->sprint("format write failed: %r")); 135 return nil; 136 } 137 sys->seek(fd, big 0, Sys->SEEKSTART); 138 return bufio->fopen(fd, Sys->OREAD); 139} 140 141Fmtfile.read(f: self Fmtfile, iob: ref Iobuf): (array of Fmtval, string) 142{ 143 (se, err) := Sexp.read(iob); 144 if(se == nil) 145 return (nil, err); 146 return rec2val(f.spec, se); 147} 148