t8.c (6231B)
1 #include "a.h" 2 /* 3 * 8. Number Registers 4 * (Reg register implementation is also here.) 5 */ 6 7 /* 8 * \nx N 9 * \n(xx N 10 * \n+x N+=M 11 * \n-x N-=M 12 * 13 * .nr R ±N M 14 * .af R c 15 * 16 * formats 17 * 1 0, 1, 2, 3, ... 18 * 001 001, 002, 003, ... 19 * i 0, i, ii, iii, iv, v, ... 20 * I 0, I, II, III, IV, V, ... 21 * a 0, a, b, ..., aa, ab, ..., zz, aaa, ... 22 * A 0, A, B, ..., AA, AB, ..., ZZ, AAA, ... 23 * 24 * \gx \g(xx return format of number register 25 * 26 * .rr R 27 */ 28 29 typedef struct Reg Reg; 30 struct Reg 31 { 32 Reg *next; 33 Rune *name; 34 Rune *val; 35 Rune *fmt; 36 int inc; 37 }; 38 39 Reg *dslist; 40 Reg *nrlist; 41 42 /* 43 * Define strings and numbers. 44 */ 45 void 46 dsnr(Rune *name, Rune *val, Reg **l) 47 { 48 Reg *s; 49 50 for(s = *l; s != nil; s = *l){ 51 if(runestrcmp(s->name, name) == 0) 52 break; 53 l = &s->next; 54 } 55 if(val == nil){ 56 if(s){ 57 *l = s->next; 58 free(s->val); 59 free(s->fmt); 60 free(s); 61 } 62 return; 63 } 64 if(s == nil){ 65 s = emalloc(sizeof(Reg)); 66 *l = s; 67 s->name = erunestrdup(name); 68 }else 69 free(s->val); 70 s->val = erunestrdup(val); 71 } 72 73 Rune* 74 getdsnr(Rune *name, Reg *list) 75 { 76 Reg *s; 77 78 for(s=list; s; s=s->next) 79 if(runestrcmp(name, s->name) == 0) 80 return s->val; 81 return nil; 82 } 83 84 void 85 ds(Rune *name, Rune *val) 86 { 87 dsnr(name, val, &dslist); 88 } 89 90 void 91 as(Rune *name, Rune *val) 92 { 93 Rune *p, *q; 94 95 p = getds(name); 96 if(p == nil) 97 p = L(""); 98 q = runemalloc(runestrlen(p)+runestrlen(val)+1); 99 runestrcpy(q, p); 100 runestrcat(q, val); 101 ds(name, q); 102 free(q); 103 } 104 105 Rune* 106 getds(Rune *name) 107 { 108 return getdsnr(name, dslist); 109 } 110 111 void 112 printds(int t) 113 { 114 int n, total; 115 Reg *s; 116 117 total = 0; 118 for(s=dslist; s; s=s->next){ 119 if(s->val) 120 n = runestrlen(s->val); 121 else 122 n = 0; 123 total += n; 124 if(!t) 125 fprint(2, "%S\t%d\n", s->name, n); 126 } 127 fprint(2, "total\t%d\n", total); 128 } 129 130 void 131 nr(Rune *name, int val) 132 { 133 Rune buf[20]; 134 135 runesnprint(buf, nelem(buf), "%d", val); 136 _nr(name, buf); 137 } 138 139 void 140 af(Rune *name, Rune *fmt) 141 { 142 Reg *s; 143 144 if(_getnr(name) == nil) 145 _nr(name, L("0")); 146 for(s=nrlist; s; s=s->next) 147 if(runestrcmp(s->name, name) == 0) 148 s->fmt = erunestrdup(fmt); 149 } 150 151 Rune* 152 getaf(Rune *name) 153 { 154 Reg *s; 155 156 for(s=nrlist; s; s=s->next) 157 if(runestrcmp(s->name, name) == 0) 158 return s->fmt; 159 return nil; 160 } 161 162 void 163 printnr(void) 164 { 165 Reg *r; 166 167 for(r=nrlist; r; r=r->next) 168 fprint(2, "%S %S %d\n", r->name, r->val, r->inc); 169 } 170 171 /* 172 * Some internal number registers are actually strings, 173 * so provide _ versions to get at them. 174 */ 175 void 176 _nr(Rune *name, Rune *val) 177 { 178 dsnr(name, val, &nrlist); 179 } 180 181 Rune* 182 _getnr(Rune *name) 183 { 184 return getdsnr(name, nrlist); 185 } 186 187 int 188 getnr(Rune *name) 189 { 190 Rune *p; 191 192 p = _getnr(name); 193 if(p == nil) 194 return 0; 195 return eval(p); 196 } 197 198 /* new register */ 199 void 200 r_nr(int argc, Rune **argv) 201 { 202 Reg *s; 203 204 if(argc < 2) 205 return; 206 if(argc < 3) 207 nr(argv[1], 0); 208 else{ 209 if(argv[2][0] == '+') 210 nr(argv[1], getnr(argv[1])+eval(argv[2]+1)); 211 else if(argv[2][0] == '-') 212 nr(argv[1], getnr(argv[1])-eval(argv[2]+1)); 213 else 214 nr(argv[1], eval(argv[2])); 215 } 216 if(argc > 3){ 217 for(s=nrlist; s; s=s->next) 218 if(runestrcmp(s->name, argv[1]) == 0) 219 s->inc = eval(argv[3]); 220 } 221 } 222 223 /* assign format */ 224 void 225 r_af(int argc, Rune **argv) 226 { 227 USED(argc); 228 229 af(argv[1], argv[2]); 230 } 231 232 /* remove register */ 233 void 234 r_rr(int argc, Rune **argv) 235 { 236 int i; 237 238 for(i=1; i<argc; i++) 239 _nr(argv[i], nil); 240 } 241 242 /* fmt integer in base 26 */ 243 void 244 alpha(Rune *buf, int n, int a) 245 { 246 int i, v; 247 248 i = 1; 249 for(v=n; v>0; v/=26) 250 i++; 251 if(i == 0) 252 i = 1; 253 buf[i] = 0; 254 while(i > 0){ 255 buf[--i] = a+n%26; 256 n /= 26; 257 } 258 } 259 260 struct romanv { 261 char *s; 262 int v; 263 } romanv[] = 264 { 265 "m", 1000, 266 "cm", 900, 267 "d", 500, 268 "cd", 400, 269 "c", 100, 270 "xc", 90, 271 "l", 50, 272 "xl", 40, 273 "x", 10, 274 "ix", 9, 275 "v", 5, 276 "iv", 4, 277 "i", 1 278 }; 279 280 /* fmt integer in roman numerals! */ 281 void 282 roman(Rune *buf, int n, int upper) 283 { 284 Rune *p; 285 char *q; 286 struct romanv *r; 287 288 if(upper) 289 upper = 'A' - 'a'; 290 if(n >= 5000 || n <= 0){ 291 runestrcpy(buf, L("-")); 292 return; 293 } 294 p = buf; 295 r = romanv; 296 while(n > 0){ 297 while(n >= r->v){ 298 for(q=r->s; *q; q++) 299 *p++ = *q + upper; 300 n -= r->v; 301 } 302 r++; 303 } 304 *p = 0; 305 } 306 307 Rune* 308 getname(void) 309 { 310 int i, c, cc; 311 static Rune buf[100]; 312 313 /* XXX add [name] syntax as in groff */ 314 c = getnext(); 315 if(c < 0) 316 return L(""); 317 if(c == '\n'){ 318 warn("newline in name\n"); 319 ungetnext(c); 320 return L(""); 321 } 322 if(c == '['){ 323 for(i=0; i<nelem(buf)-1; i++){ 324 if((c = getrune()) < 0) 325 return L(""); 326 if(c == ']'){ 327 buf[i] = 0; 328 return buf; 329 } 330 buf[i] = c; 331 } 332 return L(""); 333 } 334 if(c != '('){ 335 buf[0] = c; 336 buf[1] = 0; 337 return buf; 338 } 339 c = getnext(); 340 cc = getnext(); 341 if(c < 0 || cc < 0) 342 return L(""); 343 if(c == '\n' | cc == '\n'){ 344 warn("newline in \\n"); 345 ungetnext(cc); 346 if(c == '\n') 347 ungetnext(c); 348 } 349 buf[0] = c; 350 buf[1] = cc; 351 buf[2] = 0; 352 return buf; 353 } 354 355 /* \n - return number register */ 356 int 357 e_n(void) 358 { 359 int inc, v, l; 360 Rune *name, *fmt, buf[100]; 361 Reg *s; 362 363 inc = getnext(); 364 if(inc < 0) 365 return -1; 366 if(inc != '+' && inc != '-'){ 367 ungetnext(inc); 368 inc = 0; 369 } 370 name = getname(); 371 if(_getnr(name) == nil) 372 _nr(name, L("0")); 373 for(s=nrlist; s; s=s->next){ 374 if(runestrcmp(s->name, name) == 0){ 375 if(s->fmt == nil && !inc && s->val[0]){ 376 /* might be a string! */ 377 pushinputstring(s->val); 378 return 0; 379 } 380 v = eval(s->val); 381 if(inc){ 382 if(inc == '+') 383 v += s->inc; 384 else 385 v -= s->inc; 386 runesnprint(buf, nelem(buf), "%d", v); 387 free(s->val); 388 s->val = erunestrdup(buf); 389 } 390 fmt = s->fmt; 391 if(fmt == nil) 392 fmt = L("1"); 393 switch(fmt[0]){ 394 case 'i': 395 case 'I': 396 roman(buf, v, fmt[0]=='I'); 397 break; 398 case 'a': 399 case 'A': 400 alpha(buf, v, fmt[0]); 401 break; 402 default: 403 l = runestrlen(fmt); 404 if(l == 0) 405 l = 1; 406 runesnprint(buf, sizeof buf, "%0*d", l, v); 407 break; 408 } 409 pushinputstring(buf); 410 return 0; 411 } 412 } 413 pushinputstring(L("")); 414 return 0; 415 } 416 417 /* \g - number register format */ 418 int 419 e_g(void) 420 { 421 Rune *p; 422 423 p = getaf(getname()); 424 if(p == nil) 425 p = L("1"); 426 pushinputstring(p); 427 return 0; 428 } 429 430 void 431 r_pnr(int argc, Rune **argv) 432 { 433 USED(argc); 434 USED(argv); 435 printnr(); 436 } 437 438 void 439 t8init(void) 440 { 441 addreq(L("nr"), r_nr, -1); 442 addreq(L("af"), r_af, 2); 443 addreq(L("rr"), r_rr, -1); 444 addreq(L("pnr"), r_pnr, 0); 445 446 addesc('n', e_n, CopyMode|ArgMode|HtmlMode); 447 addesc('g', e_g, 0); 448 }