1% mathnodes.w 2% 3% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org> 4% Copyright 2012 Khaled Hosny <khaledhosny@@eglug.org> 5% 6% This file is part of LuaTeX. 7% 8% LuaTeX is free software; you can redistribute it and/or modify it under 9% the terms of the GNU General Public License as published by the Free 10% Software Foundation; either version 2 of the License, or (at your 11% option) any later version. 12% 13% LuaTeX is distributed in the hope that it will be useful, but WITHOUT 14% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16% License for more details. 17% 18% You should have received a copy of the GNU General Public License along 19% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. 20 21@ @c 22 23 24#include "ptexlib.h" 25 26@ math codes 27@c 28static sa_tree mathcode_head = NULL; 29 30#define MATHCODEHEAP 8 31 32static mathcodeval *mathcode_heap = NULL; 33static int mathcode_heapsize = MATHCODEHEAP; 34static int mathcode_heapptr = 0; 35 36/* the 0xFFFFFFFF is a flag value */ 37#define MATHCODESTACK 8 38#define MATHCODEDEFAULT 0xFFFFFFFF 39 40@ delcodes 41@c 42static sa_tree delcode_head = NULL; 43 44#define DELCODEHEAP 8 45 46static delcodeval *delcode_heap = NULL; 47static int delcode_heapsize = DELCODEHEAP; 48static int delcode_heapptr = 0; 49 50#define DELCODESTACK 4 51#define DELCODEDEFAULT 0xFFFFFFFF 52 53@ some helpers for mathcode printing 54 55@c 56#define print_hex_digit(A) do { \ 57 if ((A)>=10) print_char('A'+(A)-10); \ 58 else print_char('0'+(A)); \ 59 } while (0) 60 61#define two_hex(A) do { \ 62 print_hex_digit((A)/16); \ 63 print_hex_digit((A)%16); \ 64 } while (0) 65 66#define four_hex(A) do { \ 67 two_hex((A)/256); \ 68 two_hex((A)%256); \ 69 } while (0) 70 71#define six_hex(A) do { \ 72 two_hex((A)/65536); \ 73 two_hex(((A)%65536)/256); \ 74 two_hex((A)%256); \ 75 } while (0) 76 77@ @c 78void show_mathcode_value(mathcodeval c) 79{ 80 if (c.origin_value == xetex_mathcode) { 81 print_char('"'); 82 print_hex_digit(c.class_value); 83 print_char('"'); 84 two_hex(c.family_value); 85 print_char('"'); 86 six_hex(c.character_value); 87 } else if (c.origin_value == xetexnum_mathcode) { 88 int m; 89 m = (c.class_value + (c.family_value * 8)) * 2097152 + 90 c.character_value; 91 print_int(m); 92 } else { 93 print_char('"'); 94 if (c.class_value) { 95 print_hex_digit(c.class_value); 96 print_hex_digit(c.family_value); 97 two_hex(c.character_value); 98 } else if (c.family_value) { 99 print_hex_digit(c.family_value); 100 two_hex(c.character_value); 101 } else if (c.character_value >= 16) { 102 two_hex(c.character_value); 103 } else { 104 print_hex_digit(c.character_value); 105 } 106 } 107} 108 109@ @c 110static void show_mathcode(int n) 111{ 112 mathcodeval c = get_math_code(n); 113 if (c.origin_value == xetex_mathcode) { 114 tprint_esc("Umathcode"); 115 } else if (c.origin_value == xetexnum_mathcode) { 116 tprint_esc("Umathcodenum"); 117 } else { 118 tprint_esc("mathcode"); 119 } 120 print_int(n); 121 print_char('='); 122 show_mathcode_value(c); 123} 124 125@ @c 126static void unsavemathcode(quarterword gl) 127{ 128 sa_stack_item st; 129 if (mathcode_head->stack == NULL) 130 return; 131 while (mathcode_head->stack_ptr > 0 && 132 abs(mathcode_head->stack[mathcode_head->stack_ptr].level) 133 >= (int) gl) { 134 st = mathcode_head->stack[mathcode_head->stack_ptr]; 135 if (st.level > 0) { 136 rawset_sa_item(mathcode_head, st.code, st.value); 137 /* now do a trace message, if requested */ 138 if (int_par(tracing_restores_code) > 0) { 139 begin_diagnostic(); 140 print_char('{'); 141 tprint("restoring"); 142 print_char(' '); 143 show_mathcode(st.code); 144 print_char('}'); 145 end_diagnostic(false); 146 } 147 } 148 (mathcode_head->stack_ptr)--; 149 } 150} 151 152@ @c 153void set_math_code(int n, 154 int commandorigin, 155 int mathclass, 156 int mathfamily, int mathcharacter, quarterword level) 157{ 158 mathcodeval d; 159 d.origin_value = commandorigin; 160 d.class_value = mathclass; 161 d.family_value = mathfamily; 162 d.character_value = mathcharacter; 163 if (mathcode_heapptr == mathcode_heapsize) { 164 mathcode_heapsize += MATHCODEHEAP; 165 mathcode_heap = 166 Mxrealloc_array(mathcode_heap, mathcodeval, mathcode_heapsize); 167 } 168 mathcode_heap[mathcode_heapptr] = d; 169 set_sa_item(mathcode_head, n, (sa_tree_item) mathcode_heapptr, level); 170 mathcode_heapptr++; 171 if (int_par(tracing_assigns_code) > 0) { 172 begin_diagnostic(); 173 print_char('{'); 174 tprint("assigning"); 175 print_char(' '); 176 show_mathcode(n); 177 print_char('}'); 178 end_diagnostic(false); 179 } 180} 181 182@ @c 183mathcodeval get_math_code(int n) 184{ 185 unsigned int ret; 186 ret = get_sa_item(mathcode_head, n); 187 if (ret == MATHCODEDEFAULT) { 188 mathcodeval d; 189 d.class_value = 0; 190 d.family_value = 0; 191 d.origin_value = (n < 256 ? tex_mathcode : xetex_mathcode); 192 d.character_value = n; 193 return d; 194 } else { 195 return mathcode_heap[ret]; 196 } 197} 198 199 200@ @c 201int get_math_code_num(int n, boolean compat) 202{ 203 mathcodeval mval; 204 mval = get_math_code(n); 205 if (compat) { /* \.{\\the\\mathcode} */ 206 if (mval.class_value > 8 207 || mval.family_value > 15 208 || mval.character_value > 255) { 209 print_err("Extended mathchar used as mathchar"); 210 help2("A mathchar number must be between 0 and \"8000.", 211 "I changed this one to zero."); 212 int_error(get_math_code_num(n, false)); 213 return 0; 214 } else 215 return mval.class_value * 4096 + mval.family_value * 256 + mval.character_value; 216 } else { /* \.{\\the\\Umathcodenum} */ 217 return (mval.class_value + (mval.family_value * 8)) * (65536 * 32) + mval.character_value; 218 } 219 return 0; 220} 221 222@ @c 223static void initializemathcode(void) 224{ 225 mathcode_head = new_sa_tree(MATHCODESTACK, MATHCODEDEFAULT); 226 mathcode_heap = Mxmalloc_array(mathcodeval, MATHCODEHEAP); 227} 228 229@ @c 230static void dumpmathcode(void) 231{ 232 int k; 233 mathcodeval d; 234 dump_sa_tree(mathcode_head); 235 dump_int(mathcode_heapsize); 236 dump_int(mathcode_heapptr); 237 for (k = 0; k < mathcode_heapptr; k++) { 238 d = mathcode_heap[k]; 239 dump_int(d.origin_value); 240 dump_int(d.class_value); 241 dump_int(d.family_value); 242 dump_int(d.character_value); 243 } 244} 245 246static void undumpmathcode(void) 247{ 248 int k, x; 249 mathcodeval d; 250 mathcode_head = undump_sa_tree(); 251 undump_int(mathcode_heapsize); 252 undump_int(mathcode_heapptr); 253 mathcode_heap = Mxmalloc_array(mathcodeval, mathcode_heapsize); 254 for (k = 0; k < mathcode_heapptr; k++) { 255 undump_int(x); 256 d.origin_value = x; 257 undump_int(x); 258 d.class_value = x; 259 undump_int(x); 260 d.family_value = x; 261 undump_int(x); 262 d.character_value = x; 263 mathcode_heap[k] = d; 264 } 265 d.origin_value = 0; 266 d.class_value = 0; 267 d.family_value = 0; 268 d.character_value = 0; 269 for (k = mathcode_heapptr; k < mathcode_heapsize; k++) { 270 mathcode_heap[k] = d; 271 } 272} 273 274@ @c 275static void show_delcode(int n) 276{ 277 delcodeval c; 278 c = get_del_code(n); 279 if (c.origin_value == tex_mathcode) { 280 tprint_esc("delcode"); 281 } else if (c.origin_value == xetex_mathcode) { 282 tprint_esc("Udelcode"); 283 } else if (c.origin_value == xetexnum_mathcode) { 284 tprint_esc("Udelcodenum"); 285 } 286 print_int(n); 287 print_char('='); 288 if (c.small_family_value < 0) { 289 print_char('-'); 290 print_char('1'); 291 } else { 292 if (c.origin_value == tex_mathcode) { 293 print_char('"'); 294 print_hex_digit(c.small_family_value); 295 two_hex(c.small_character_value); 296 print_hex_digit(c.large_family_value); 297 two_hex(c.large_character_value); 298 } else if (c.origin_value == xetex_mathcode) { 299 print_char('"'); 300 two_hex(c.small_family_value); 301 six_hex(c.small_character_value); 302 } else if (c.origin_value == xetexnum_mathcode) { 303 int m; 304 m = c.small_family_value * 2097152 + c.small_character_value; 305 print_int(m); 306 } 307 } 308} 309 310 311 312@ TODO: clean up the heap 313@c 314static void unsavedelcode(quarterword gl) 315{ 316 sa_stack_item st; 317 if (delcode_head->stack == NULL) 318 return; 319 while (delcode_head->stack_ptr > 0 && 320 abs(delcode_head->stack[delcode_head->stack_ptr].level) 321 >= (int) gl) { 322 st = delcode_head->stack[delcode_head->stack_ptr]; 323 if (st.level > 0) { 324 rawset_sa_item(delcode_head, st.code, st.value); 325 /* now do a trace message, if requested */ 326 if (int_par(tracing_restores_code) > 0) { 327 begin_diagnostic(); 328 print_char('{'); 329 tprint("restoring"); 330 print_char(' '); 331 show_delcode(st.code); 332 print_char('}'); 333 end_diagnostic(false); 334 } 335 } 336 (delcode_head->stack_ptr)--; 337 } 338 339} 340 341@ @c 342void set_del_code(int n, 343 int commandorigin, 344 int smathfamily, 345 int smathcharacter, 346 int lmathfamily, int lmathcharacter, quarterword gl) 347{ 348 delcodeval d; 349 d.class_value = 0; 350 d.origin_value = commandorigin; 351 d.small_family_value = smathfamily; 352 d.small_character_value = smathcharacter; 353 d.large_family_value = lmathfamily; 354 d.large_character_value = lmathcharacter; 355 if (delcode_heapptr == delcode_heapsize) { 356 delcode_heapsize += DELCODEHEAP; 357 delcode_heap = 358 Mxrealloc_array(delcode_heap, delcodeval, delcode_heapsize); 359 } 360 delcode_heap[delcode_heapptr] = d; 361 set_sa_item(delcode_head, n, (sa_tree_item) delcode_heapptr, gl); 362 if (int_par(tracing_assigns_code) > 0) { 363 begin_diagnostic(); 364 print_char('{'); 365 tprint("assigning"); 366 print_char(' '); 367 show_delcode(n); 368 print_char('}'); 369 end_diagnostic(false); 370 } 371 delcode_heapptr++; 372} 373 374@ @c 375delcodeval get_del_code(int n) 376{ 377 unsigned ret; 378 ret = get_sa_item(delcode_head, n); 379 if (ret == DELCODEDEFAULT) { 380 delcodeval d; 381 d.class_value = 0; 382 d.origin_value = tex_mathcode; 383 d.small_family_value = -1; 384 d.small_character_value = 0; 385 d.large_family_value = 0; 386 d.large_character_value = 0; 387 return d; 388 } else { 389 return delcode_heap[ret]; 390 } 391} 392 393@ this really only works for old-style delcodes! 394 395@c 396int get_del_code_num(int n) 397{ 398 unsigned ret; 399 ret = get_sa_item(delcode_head, n); 400 if (ret == DELCODEDEFAULT) { 401 return -1; 402 } else { 403 delcodeval d = delcode_heap[ret]; 404 if (d.origin_value == tex_mathcode) { 405 return ((d.small_family_value * 256 + 406 d.small_character_value) * 4096 + 407 (d.large_family_value * 256) + d.large_character_value); 408 } else { 409 return -1; 410 } 411 } 412} 413 414@ @c 415static void initializedelcode(void) 416{ 417 delcode_head = new_sa_tree(DELCODESTACK, DELCODEDEFAULT); 418 delcode_heap = Mxmalloc_array(delcodeval, DELCODEHEAP); 419} 420 421@ @c 422static void dumpdelcode(void) 423{ 424 int k; 425 delcodeval d; 426 dump_sa_tree(delcode_head); 427 dump_int(delcode_heapsize); 428 dump_int(delcode_heapptr); 429 for (k = 0; k < delcode_heapptr; k++) { 430 d = delcode_heap[k]; 431 dump_int(d.origin_value); 432 dump_int(d.class_value); 433 dump_int(d.small_family_value); 434 dump_int(d.small_character_value); 435 dump_int(d.large_family_value); 436 dump_int(d.large_character_value); 437 } 438} 439 440static void undumpdelcode(void) 441{ 442 int k; 443 delcodeval d; 444 delcode_head = undump_sa_tree(); 445 undump_int(delcode_heapsize); 446 undump_int(delcode_heapptr); 447 delcode_heap = Mxmalloc_array(delcodeval, delcode_heapsize); 448 for (k = 0; k < delcode_heapptr; k++) { 449 undump_int(d.origin_value); 450 undump_int(d.class_value); 451 undump_int(d.small_family_value); 452 undump_int(d.small_character_value); 453 undump_int(d.large_family_value); 454 undump_int(d.large_character_value); 455 delcode_heap[k] = d; 456 } 457 d.origin_value = tex_mathcode; 458 d.class_value = 0; 459 d.small_family_value = -1; 460 d.small_character_value = 0; 461 d.large_family_value = 0; 462 d.large_character_value = 0; 463 for (k = delcode_heapptr; k < delcode_heapsize; k++) { 464 delcode_heap[k] = d; 465 } 466} 467 468@ @c 469void unsave_math_codes(quarterword grouplevel) 470{ 471 unsavemathcode(grouplevel); 472 unsavedelcode(grouplevel); 473} 474 475@ @c 476void initialize_math_codes(void) 477{ 478 initializemathcode(); 479 initializedelcode(); 480} 481 482@ @c 483void free_math_codes(void) 484{ 485 destroy_sa_tree(mathcode_head); 486 xfree(mathcode_heap); 487 destroy_sa_tree(delcode_head); 488 xfree(delcode_heap); 489} 490 491@ @c 492void dump_math_codes(void) 493{ 494 dumpmathcode(); 495 dumpdelcode(); 496} 497 498void undump_math_codes(void) 499{ 500 undumpmathcode(); 501 undumpdelcode(); 502} 503