1implement Convcs; 2 3include "sys.m"; 4include "cfg.m"; 5include "convcs.m"; 6 7DEFCSFILE : con "/lib/convcs/charsets"; 8 9sys : Sys; 10cfg : Cfg; 11 12Record, Tuple : import cfg; 13 14init(csfile : string) : string 15{ 16 sys = load Sys Sys->PATH; 17 cfg = load Cfg Cfg->PATH; 18 if (cfg == nil) 19 return sys->sprint("cannot load module %s: %r", Cfg->PATH); 20 if (csfile == nil) 21 csfile = DEFCSFILE; 22 err := cfg->init(csfile); 23 if (err != nil) { 24 cfg = nil; 25 return err; 26 } 27 return nil; 28} 29 30getbtos(cs : string) : (Btos, string) 31{ 32 cs = normalize(cs); 33 (rec, err) := csalias(cs); 34 if (err != nil) 35 return (nil, err); 36 37 (path, btostup) := rec.lookup("btos"); 38 if (path == nil) 39 return (nil, sys->sprint("no converter for %s", cs)); 40 arg := btostup.lookup("arg"); 41 42 btos := load Btos path; 43 if (btos == nil) 44 return (nil, sys->sprint("cannot load converter: %r")); 45 err = btos->init(arg); 46 if (err != nil) 47 return (nil, err); 48 return (btos, nil); 49} 50 51getstob(cs : string) : (Stob, string) 52{ 53 cs = normalize(cs); 54 (rec, err) := csalias(cs); 55 if (err != nil) 56 return (nil, err); 57 58 (path, stobtup) := rec.lookup("stob"); 59 if (path == nil) 60 return (nil, sys->sprint("no converter for %s", cs)); 61 arg := stobtup.lookup("arg"); 62 63 stob := load Stob path; 64 if (stob == nil) 65 return (nil, sys->sprint("cannot load converter: %r")); 66 err = stob->init(arg); 67 if (err != nil) 68 return (nil, err); 69 return (stob, nil); 70} 71 72csalias(cs : string) : (ref Cfg->Record, string) 73{ 74 # search out charset record - allow for one level of renaming 75 for (i := 0; i < 2; i++) { 76 recs := cfg->lookup(cs); 77 if (recs == nil) 78 return (nil, sys->sprint("unknown charset %s", cs)); 79 (val, rec) := hd recs; 80 if (val != nil) { 81 cs = val; 82 continue; 83 } 84 return (rec, nil); 85 } 86 return (nil, sys->sprint("too man aliases for %s\n", cs)); 87} 88 89enumcs() : list of (string, string, int) 90{ 91 d : list of (string, string, int); 92 for (csl := cfg->getkeys(); csl != nil; csl = tl csl) { 93 cs := hd csl; 94 recs := cfg->lookup(cs); 95 if (recs == nil) 96 continue; # shouldn't happen! 97 (val, rec) := hd recs; 98 if (val != nil) 99 # an alias - ignore 100 continue; 101 102 (btos, nil) := rec.lookup("btos"); 103 (stob, nil) := rec.lookup("stob"); 104 105 if (btos == nil && stob == nil) 106 continue; 107 mode := 0; 108 if (btos != nil) 109 mode = BTOS; 110 if (stob != nil) 111 mode |= STOB; 112 113 (desc, nil) := rec.lookup("desc"); 114 if (desc == nil) 115 desc = cs; 116 117 d = (cs, desc, mode) :: d; 118 } 119 # d is in reverse order to that in the csfile file 120 l : list of (string, string, int); 121 for (; d != nil; d = tl d) 122 l = hd d :: l; 123 return l; 124} 125 126aliases(cs : string) : (string, list of string) 127{ 128 cs = normalize(cs); 129 (mainrec, err) := csalias(cs); 130 if (err != nil) 131 return (err, nil); 132 133 cs = (hd (hd mainrec.tuples).attrs).name; 134 135 (desc, nil) := mainrec.lookup("desc"); 136 if (desc == nil) 137 desc = cs; 138 139 al := cs :: nil; 140 for (csl := cfg->getkeys(); csl != nil; csl = tl csl) { 141 name := hd csl; 142 recs := cfg->lookup(name); 143 if (recs == nil) 144 continue; # shouldn't happen! 145 (val, nil) := hd recs; 146 if (val != cs) 147 continue; 148 al = name :: al; 149 } 150 151 r : list of string; 152 for (; al != nil; al = tl al) 153 r = hd al :: r; 154 return (desc, r); 155} 156 157normalize(s : string) : string 158{ 159 for (i := 0; i < len s; i++) { 160 r := s[i]; 161 if (r >= 'A' && r <= 'Z') 162 s[i] = r + ('a' - 'A'); 163 } 164 return s; 165} 166