Print this page
Address Robert's feedback


   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Jason King
  14  */
  15 
  16 #include <sys/debug.h>
  17 #include <sys/sysmacros.h>
  18 #include <string.h>
  19 #include <errno.h>
  20 #include <stdlib.h>
  21 #include "sysdemangle_int.h"
  22 #include "cpp.h"
  23 
  24 #define CHUNK_SIZE  (8U)
  25 
  26 /*
  27  * A name_t is essentially a stack of str_pair_t's.  Generally, the parsing
  28  * code will push (via name_add() or the like) portions of the demangled
  29  * name into a name_t, and periodically combine them via name_join().
  30  *
  31  * As such it should be noted that since items are added at the end of
  32  * name_t->nm_items, the numbering of name_at() starts at the end
  33  * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
  34  *
  35  * It should also be noted that for name_t's, adding is a move operation in
  36  * that it takes ownership of the passed in string/str_t/etc
  37  */
  38 
  39 void
  40 name_init(name_t *n, sysdem_ops_t *ops)
  41 {
  42         (void) memset(n, 0, sizeof (*n));


 134 
 135         if (!name_reserve(n, 1))
 136                 return (B_FALSE);
 137 
 138         if (l != NULL) {
 139                 sp.strp_l = *l;
 140                 (void) memset(l, 0, sizeof (*l));
 141         }
 142 
 143         if (r != NULL) {
 144                 sp.strp_r = *r;
 145                 (void) memset(r, 0, sizeof (*r));
 146         }
 147 
 148         n->nm_items[n->nm_len++] = sp;
 149 
 150         return (B_TRUE);
 151 }
 152 
 153 str_pair_t *
 154 name_at(name_t *n, size_t idx)
 155 {
 156         if (n->nm_len == 0)
 157                 return (NULL);
 158 
 159         ASSERT3U(idx, <=, n->nm_len);
 160         return (&n->nm_items[n->nm_len - idx - 1]);
 161 }
 162 
 163 str_pair_t *
 164 name_top(name_t *n)
 165 {
 166         return (name_at(n, 0));
 167 }
 168 
 169 str_pair_t *
 170 name_pop(name_t *n, str_pair_t *sp)
 171 {
 172         if (n->nm_len == 0)
 173                 return (NULL);
 174 
 175         str_pair_t *top = name_top(n);
 176 
 177         if (sp != NULL) {
 178                 *sp = *top;
 179                 (void) memset(top, 0, sizeof (*top));
 180         } else {
 181                 str_pair_fini(top);
 182         }
 183 
 184         n->nm_len--;
 185         return (sp);
 186 }
 187 
 188 boolean_t
 189 name_join(name_t *n, size_t amt, const char *sep)
 190 {
 191         str_pair_t *sp = NULL;
 192         str_t res = { 0 };
 193         size_t seplen = strlen(sep);
 194 
 195         ASSERT3U(amt, <=, n->nm_len);
 196 
 197         /*
 198          * A join of 0 elements places an empty string on the stack.  This
 199          * simplifies code that wants to do things like:
 200          *   name_join(...); name_fmt(.., "({0})", ...)
 201          */
 202         if (amt == 0) {
 203                 name_add(n, "", 0, "", 0);
 204                 return (B_TRUE);
 205         }
 206         
 207         /* A join of 1 element just implies merging the top str_pair_t */
 208         if (amt == 1) {
 209                 ASSERT3U(name_len(n), >, 0);
 210                 return (str_pair_merge(name_top(n)));
 211         }
 212 
 213         (void) str_init(&res, n->nm_ops);
 214 
 215         sp = name_at(n, amt - 1);
 216         for (size_t i = 0; i < amt; i++) {
 217                 if (i > 0) {
 218                         if (!str_append(&res, sep, seplen))
 219                                 goto error;
 220                 }
 221 
 222                 if (!str_append_str(&res, &sp->strp_l))
 223                         goto error;
 224                 if (!str_append_str(&res, &sp->strp_r))
 225                         goto error;
 226 
 227                 sp++;
 228         }
 229 
 230         for (size_t i = 0; i < amt; i++)
 231                 (void) name_pop(n, NULL);
 232 
 233         /* since we've removed at least 1 entry, this should always succeed */
 234         VERIFY(name_add_str(n, &res, NULL));
 235         return (B_TRUE);
 236 
 237 error:
 238         str_fini(&res);
 239         return (B_FALSE);
 240 }
 241 
 242 static boolean_t
 243 name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
 244 {
 245         const char *p;
 246         long max = -1;
 247 
 248         if (fmt == NULL)
 249                 return (B_TRUE);
 250 
 251         for (p = fmt; *p != '\0'; p++) {
 252                 if (*p != '{') {
 253                         str_append_c(s, *p);
 254                         continue;
 255                 }
 256 
 257                 errno = 0;
 258                 char *q = NULL;
 259                 long val = strtol(p + 1, &q, 10);
 260 
 261                 ASSERT(val != 0 || errno == 0);
 262                 ASSERT3U(val, <, n->nm_len);
 263 
 264                 str_pair_t *sp = name_at(n, val);
 265 
 266                 if (val > max)
 267                         max = val;
 268 
 269                 switch (q[0]) {
 270                 case '}':
 271                         if (!str_append_str(s, &sp->strp_l))
 272                                 return (B_FALSE);
 273                         if (!str_append_str(s, &sp->strp_r))
 274                                 return (B_FALSE);
 275                         p = q;
 276                         continue;
 277                 case ':':
 278                         switch (q[1]) {
 279                         case 'L':
 280                                 if (!str_append_str(s, &sp->strp_l))
 281                                         return (B_FALSE);
 282                                 break;
 283                         case 'R':
 284                                 if (!str_append_str(s, &sp->strp_r))
 285                                         return (B_FALSE);
 286                                 break;
 287                         }
 288 
 289                         p = q + 2;
 290                         VERIFY(*p == '}');
 291                         break;
 292                 }
 293         }
 294 
 295         if (*maxp < max)
 296                 *maxp = max;
 297 
 298         return (B_TRUE);
 299 }
 300 
 301 /*
 302  * replace a number of elements in the name stack with a formatted string
 303  * for format is a plain string with optional {nnn} or {nnn:L|R} substitutions
 304  * where nnn is the stack position of an element and it's contents (both
 305  * left and right pieces) are inserted.  Optionally, only the left or
 306  * right piece can specified using :L|R e.g. {2:L}{3}{2:R} would insert
 307  * the left piece of element 2, all of element 3, then the right piece of
 308  * element 2.
 309  *
 310  * Once complete, all elements up to the deepest one references are popped
 311  * off the stack, and the resulting formatted string is pushed into n.
 312  *
 313  * This could be done as a sequence of push & pops, but this makes the
 314  * intended output far clearer to see.
 315  */
 316 boolean_t
 317 name_fmt(name_t *n, const char *fmt_l, const char *fmt_r)
 318 {
 319         str_pair_t res;
 320         long max = -1;
 321 
 322         (void) str_pair_init(&res, n->nm_ops);
 323 
 324         if (!name_reserve(n, 1))
 325                 return (B_FALSE);
 326 
 327         if (!name_fmt_s(n, &res.strp_l, fmt_l, &max))
 328                 goto error;
 329         if (!name_fmt_s(n, &res.strp_r, fmt_r, &max))
 330                 goto error;
 331 
 332         if (max >= 0) {
 333                 for (size_t i = 0; i <= max; i++)
 334                         (void) name_pop(n, NULL);
 335         }
 336 
 337         n->nm_items[n->nm_len++] = res;
 338         return (B_TRUE);
 339 
 340 error:
 341         str_pair_fini(&res);
 342         return (B_FALSE);
 343 }
 344 
 345 /*
 346  * The substitution list is a list of name_t's that get added as the
 347  * demangled name is parsed.  Adding a name_t to the substitution list
 348  * is a copy operation, and likewise inserting a substitution into a name_t
 349  * is also a copy operation.
 350  */
 351 void
 352 sub_init(sub_t *sub, sysdem_ops_t *ops)
 353 {
 354         (void) memset(sub, 0, sizeof (*sub));


 412 
 413 /* save the element of n (up to depth elements deep) as a substitution */
 414 boolean_t
 415 sub_save(sub_t *sub, const name_t *n, size_t depth)
 416 {
 417         if (depth == 0)
 418                 return (B_TRUE);
 419 
 420         if (!sub_reserve(sub, 1))
 421                 return (B_FALSE);
 422 
 423         name_t *dest = &sub->sub_items[sub->sub_len++];
 424         name_init(dest, sub->sub_ops);
 425 
 426         if (!name_reserve(dest, depth)) {
 427                 name_fini(dest);
 428                 sub->sub_len--;
 429                 return (B_FALSE);
 430         }
 431 
 432         const str_pair_t *src_sp = name_at((name_t *)n, depth - 1);
 433 
 434         for (size_t i = 0; i < depth; i++, src_sp++) {
 435                 str_pair_t copy = { 0 };
 436                 str_pair_init(&copy, n->nm_ops);
 437                 if (!str_pair_copy(src_sp, &copy)) {
 438                         str_pair_fini(&copy);
 439                         name_fini(dest);
 440                         return (B_FALSE);
 441                 }
 442 
 443                 VERIFY(name_add_str(dest, &copy.strp_l, &copy.strp_r));
 444         }
 445 
 446         return (B_TRUE);
 447 }
 448 
 449 /* push substitution idx onto n */
 450 boolean_t
 451 sub_substitute(const sub_t *sub, size_t idx, name_t *n)
 452 {
 453         ASSERT3U(idx, <, sub->sub_len);
 454 
 455         const name_t *src = &sub->sub_items[idx];
 456         const str_pair_t *sp = src->nm_items;
 457         size_t save = name_len(n);
 458 
 459         for (size_t i = 0; i < src->nm_len; i++, sp++) {
 460                 str_pair_t copy = { 0 };
 461 
 462                 if (!str_pair_copy(sp, &copy))
 463                         goto fail;
 464 
 465                 if (!name_add_str(n, &copy.strp_l, &copy.strp_r))
 466                         goto fail;
 467         }
 468 
 469         return (B_TRUE);
 470 
 471 fail:
 472         for (size_t i = 0; i < name_len(n) - save; i++)
 473                 (void) name_pop(n, NULL);
 474         return (B_FALSE);
 475 }
 476 
 477 void
 478 sub_pop(sub_t *sub)
 479 {
 480         name_t *top = &sub->sub_items[--sub->sub_len];
 481         name_fini(top);
 482 }
 483 
 484 /*
 485  * Templates can use substitutions for it's arguments (using T instead of
 486  * S).  Since templates can nest however, each nesting requires a new
 487  * set of substitutions.  As such a new, empty list of template substitutions
 488  * is pushed onto cpp_templ each time templates are nested, and popped at
 489  * the end of the current template argument list.
 490  */
 491 static boolean_t
 492 templ_reserve(templ_t *tpl, size_t n)
 493 {


 525         xfree(tpl->tpl_ops, tpl->tpl_items, tpl->tpl_size * sizeof (sub_t));
 526         sysdem_ops_t *ops = tpl->tpl_ops;
 527         (void) memset(tpl, 0, sizeof (*tpl));
 528         tpl->tpl_ops = ops;
 529 }
 530 
 531 boolean_t
 532 templ_push(templ_t *tpl)
 533 {
 534         if (!templ_reserve(tpl, 1))
 535                 return (B_FALSE);
 536 
 537         sub_t *sub = &tpl->tpl_items[tpl->tpl_len++];
 538         sub_init(sub, tpl->tpl_ops);
 539         return (B_TRUE);
 540 }
 541 
 542 void
 543 templ_pop(templ_t *tpl)
 544 {
 545         ASSERT(!templ_empty(tpl));
 546 
 547         sub_t *sub = &tpl->tpl_items[--tpl->tpl_len];
 548         sub_fini(sub);
 549 }
 550 
 551 sub_t *
 552 templ_top(templ_t *tpl)
 553 {
 554         if (tpl->tpl_len == 0)
 555                 return (NULL);
 556         return (&tpl->tpl_items[tpl->tpl_len - 1]);
 557 }
 558 
 559 boolean_t
 560 templ_empty(const templ_t *tpl)
 561 {
 562         return ((tpl->tpl_len == 0) ? B_TRUE : B_FALSE);
 563 }
 564 
 565 size_t
 566 templ_top_len(const templ_t *tpl)
 567 {
 568         const sub_t *sub = templ_top((templ_t *)tpl);
 569 
 570         return (sub->sub_len);
 571 }
 572 
 573 boolean_t
 574 templ_sub(const templ_t *tpl, size_t idx, name_t *n)
 575 {
 576         const sub_t *sub = templ_top((templ_t *)tpl);
 577 
 578         return (sub_substitute(sub, idx, n));
 579 }
 580 
 581 boolean_t
 582 templ_save(const name_t *n, size_t amt, templ_t *tpl)
 583 {
 584         ASSERT3U(tpl->tpl_len, >, 0);
 585 
 586         sub_t *s = templ_top(tpl);
 587         boolean_t res = B_TRUE;
 588 
 589         /* a bit of a hack -- want an 'empty' entry when saving 0 params */
 590         if (amt == 0) {
 591                 name_t name = { 0 };
 592 
 593                 name_init(&name, tpl->tpl_ops);
 594                 res &= name_add(&name, "", 0, "", 0);
 595                 if (res)
 596                         res &= sub_save(s, &name, 1);
 597                 name_fini(&name);
 598         } else {
 599                 res &= sub_save(s, n, amt);
 600         }
 601 
 602         return (res);
 603 }


   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Jason King
  14  */
  15 
  16 #include <sys/debug.h>
  17 #include <sys/sysmacros.h>
  18 #include <string.h>
  19 #include <errno.h>
  20 #include <stdlib.h>
  21 #include "sysdemangle_int.h"
  22 #include "cxx.h"
  23 
  24 #define CHUNK_SIZE  (8U)
  25 
  26 /*
  27  * A name_t is essentially a stack of str_pair_t's.  Generally, the parsing
  28  * code will push (via name_add() or the like) portions of the demangled
  29  * name into a name_t, and periodically combine them via name_join().
  30  *
  31  * As such it should be noted that since items are added at the end of
  32  * name_t->nm_items, the numbering of name_at() starts at the end
  33  * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
  34  *
  35  * It should also be noted that for name_t's, adding is a move operation in
  36  * that it takes ownership of the passed in string/str_t/etc
  37  */
  38 
  39 void
  40 name_init(name_t *n, sysdem_ops_t *ops)
  41 {
  42         (void) memset(n, 0, sizeof (*n));


 134 
 135         if (!name_reserve(n, 1))
 136                 return (B_FALSE);
 137 
 138         if (l != NULL) {
 139                 sp.strp_l = *l;
 140                 (void) memset(l, 0, sizeof (*l));
 141         }
 142 
 143         if (r != NULL) {
 144                 sp.strp_r = *r;
 145                 (void) memset(r, 0, sizeof (*r));
 146         }
 147 
 148         n->nm_items[n->nm_len++] = sp;
 149 
 150         return (B_TRUE);
 151 }
 152 
 153 str_pair_t *
 154 name_at(const name_t *n, size_t idx)
 155 {
 156         VERIFY(!name_empty(n));
 157         VERIFY3U(idx, <, n->nm_len);


 158         return (&n->nm_items[n->nm_len - idx - 1]);
 159 }
 160 
 161 str_pair_t *
 162 name_top(name_t *n)
 163 {
 164         return (name_at(n, 0));
 165 }
 166 
 167 void
 168 name_pop(name_t *n, str_pair_t *sp)
 169 {
 170         if (n->nm_len == 0)
 171                 return;
 172 
 173         str_pair_t *top = name_top(n);
 174 
 175         if (sp != NULL) {
 176                 *sp = *top;
 177                 (void) memset(top, 0, sizeof (*top));
 178         } else {
 179                 str_pair_fini(top);
 180         }
 181 
 182         n->nm_len--;

 183 }
 184 
 185 boolean_t
 186 name_join(name_t *n, size_t amt, const char *sep)
 187 {
 188         str_pair_t *sp = NULL;
 189         str_t res = { 0 };
 190         size_t seplen = strlen(sep);
 191 
 192         VERIFY3U(amt, <=, n->nm_len);
 193 
 194         /*
 195          * A join of 0 elements places an empty string on the stack.  This
 196          * simplifies code that wants to do things like:
 197          *   name_join(...); name_fmt(.., "({0})", ...)
 198          */
 199         if (amt == 0) {
 200                 name_add(n, "", 0, "", 0);
 201                 return (B_TRUE);
 202         }
 203 
 204         /* A join of 1 element just implies merging the top str_pair_t */
 205         if (amt == 1) {
 206                 VERIFY3U(name_len(n), >, 0);
 207                 return (str_pair_merge(name_top(n)));
 208         }
 209 
 210         (void) str_init(&res, n->nm_ops);
 211 
 212         sp = name_at(n, amt - 1);
 213         for (size_t i = 0; i < amt; i++) {
 214                 if (i > 0) {
 215                         if (!str_append(&res, sep, seplen))
 216                                 goto error;
 217                 }
 218 
 219                 if (!str_append_str(&res, &sp->strp_l))
 220                         goto error;
 221                 if (!str_append_str(&res, &sp->strp_r))
 222                         goto error;
 223 
 224                 sp++;
 225         }
 226 
 227         for (size_t i = 0; i < amt; i++)
 228                 name_pop(n, NULL);
 229 
 230         /* since we've removed at least 1 entry, this should always succeed */
 231         VERIFY(name_add_str(n, &res, NULL));
 232         return (B_TRUE);
 233 
 234 error:
 235         str_fini(&res);
 236         return (B_FALSE);
 237 }
 238 
 239 static boolean_t
 240 name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
 241 {
 242         const char *p;
 243         long max = -1;
 244 
 245         if (fmt == NULL)
 246                 return (B_TRUE);
 247 
 248         for (p = fmt; *p != '\0'; p++) {
 249                 if (*p != '{') {
 250                         str_append_c(s, *p);
 251                         continue;
 252                 }
 253 
 254                 errno = 0;
 255                 char *q = NULL;
 256                 long val = strtol(p + 1, &q, 10);
 257 
 258                 VERIFY(val != 0 || errno == 0);
 259                 VERIFY3U(val, <, n->nm_len);
 260 
 261                 str_pair_t *sp = name_at(n, val);
 262 
 263                 if (val > max)
 264                         max = val;
 265 
 266                 switch (q[0]) {
 267                 case '}':
 268                         if (!str_append_str(s, &sp->strp_l))
 269                                 return (B_FALSE);
 270                         if (!str_append_str(s, &sp->strp_r))
 271                                 return (B_FALSE);
 272                         p = q;
 273                         continue;
 274                 case ':':
 275                         switch (q[1]) {
 276                         case 'L':
 277                                 if (!str_append_str(s, &sp->strp_l))
 278                                         return (B_FALSE);
 279                                 break;
 280                         case 'R':
 281                                 if (!str_append_str(s, &sp->strp_r))
 282                                         return (B_FALSE);
 283                                 break;
 284                         }
 285 
 286                         p = q + 2;
 287                         VERIFY(*p == '}');
 288                         break;
 289                 }
 290         }
 291 
 292         if (*maxp < max)
 293                 *maxp = max;
 294 
 295         return (B_TRUE);
 296 }
 297 
 298 /*
 299  * Replace a number of elements in the name stack with a formatted string
 300  * for format is a plain string with optional {nnn} or {nnn:L|R} substitutions
 301  * where nnn is the stack position of an element and it's contents (both
 302  * left and right pieces) are inserted.  Optionally, only the left or
 303  * right piece can specified using :L|R e.g. {2:L}{3}{2:R} would insert
 304  * the left piece of element 2, all of element 3, then the right piece of
 305  * element 2.
 306  *
 307  * Once complete, all elements up to the deepest one references are popped
 308  * off the stack, and the resulting formatted string is pushed into n.
 309  *
 310  * This could be done as a sequence of push & pops, but this makes the
 311  * intended output far clearer to see.
 312  */
 313 boolean_t
 314 name_fmt(name_t *n, const char *fmt_l, const char *fmt_r)
 315 {
 316         str_pair_t res;
 317         long max = -1;
 318 
 319         (void) str_pair_init(&res, n->nm_ops);
 320 
 321         if (!name_reserve(n, 1))
 322                 return (B_FALSE);
 323 
 324         if (!name_fmt_s(n, &res.strp_l, fmt_l, &max))
 325                 goto error;
 326         if (!name_fmt_s(n, &res.strp_r, fmt_r, &max))
 327                 goto error;
 328 
 329         if (max >= 0) {
 330                 for (size_t i = 0; i <= max; i++)
 331                         name_pop(n, NULL);
 332         }
 333 
 334         n->nm_items[n->nm_len++] = res;
 335         return (B_TRUE);
 336 
 337 error:
 338         str_pair_fini(&res);
 339         return (B_FALSE);
 340 }
 341 
 342 /*
 343  * The substitution list is a list of name_t's that get added as the
 344  * demangled name is parsed.  Adding a name_t to the substitution list
 345  * is a copy operation, and likewise inserting a substitution into a name_t
 346  * is also a copy operation.
 347  */
 348 void
 349 sub_init(sub_t *sub, sysdem_ops_t *ops)
 350 {
 351         (void) memset(sub, 0, sizeof (*sub));


 409 
 410 /* save the element of n (up to depth elements deep) as a substitution */
 411 boolean_t
 412 sub_save(sub_t *sub, const name_t *n, size_t depth)
 413 {
 414         if (depth == 0)
 415                 return (B_TRUE);
 416 
 417         if (!sub_reserve(sub, 1))
 418                 return (B_FALSE);
 419 
 420         name_t *dest = &sub->sub_items[sub->sub_len++];
 421         name_init(dest, sub->sub_ops);
 422 
 423         if (!name_reserve(dest, depth)) {
 424                 name_fini(dest);
 425                 sub->sub_len--;
 426                 return (B_FALSE);
 427         }
 428 
 429         const str_pair_t *src_sp = name_at(n, depth - 1);
 430 
 431         for (size_t i = 0; i < depth; i++, src_sp++) {
 432                 str_pair_t copy = { 0 };
 433                 str_pair_init(&copy, n->nm_ops);
 434                 if (!str_pair_copy(src_sp, &copy)) {
 435                         str_pair_fini(&copy);
 436                         name_fini(dest);
 437                         return (B_FALSE);
 438                 }
 439 
 440                 VERIFY(name_add_str(dest, &copy.strp_l, &copy.strp_r));
 441         }
 442 
 443         return (B_TRUE);
 444 }
 445 
 446 /* push substitution idx onto n */
 447 boolean_t
 448 sub_substitute(const sub_t *sub, size_t idx, name_t *n)
 449 {
 450         VERIFY3U(idx, <, sub->sub_len);
 451 
 452         const name_t *src = &sub->sub_items[idx];
 453         const str_pair_t *sp = src->nm_items;
 454         size_t save = name_len(n);
 455 
 456         for (size_t i = 0; i < src->nm_len; i++, sp++) {
 457                 str_pair_t copy = { 0 };
 458 
 459                 if (!str_pair_copy(sp, &copy))
 460                         goto fail;
 461 
 462                 if (!name_add_str(n, &copy.strp_l, &copy.strp_r))
 463                         goto fail;
 464         }
 465 
 466         return (B_TRUE);
 467 
 468 fail:
 469         for (size_t i = 0; i < name_len(n) - save; i++)
 470                 name_pop(n, NULL);
 471         return (B_FALSE);
 472 }
 473 
 474 void
 475 sub_pop(sub_t *sub)
 476 {
 477         name_t *top = &sub->sub_items[--sub->sub_len];
 478         name_fini(top);
 479 }
 480 
 481 /*
 482  * Templates can use substitutions for it's arguments (using T instead of
 483  * S).  Since templates can nest however, each nesting requires a new
 484  * set of substitutions.  As such a new, empty list of template substitutions
 485  * is pushed onto cpp_templ each time templates are nested, and popped at
 486  * the end of the current template argument list.
 487  */
 488 static boolean_t
 489 templ_reserve(templ_t *tpl, size_t n)
 490 {


 522         xfree(tpl->tpl_ops, tpl->tpl_items, tpl->tpl_size * sizeof (sub_t));
 523         sysdem_ops_t *ops = tpl->tpl_ops;
 524         (void) memset(tpl, 0, sizeof (*tpl));
 525         tpl->tpl_ops = ops;
 526 }
 527 
 528 boolean_t
 529 templ_push(templ_t *tpl)
 530 {
 531         if (!templ_reserve(tpl, 1))
 532                 return (B_FALSE);
 533 
 534         sub_t *sub = &tpl->tpl_items[tpl->tpl_len++];
 535         sub_init(sub, tpl->tpl_ops);
 536         return (B_TRUE);
 537 }
 538 
 539 void
 540 templ_pop(templ_t *tpl)
 541 {
 542         VERIFY(!templ_empty(tpl));
 543 
 544         sub_t *sub = &tpl->tpl_items[--tpl->tpl_len];
 545         sub_fini(sub);
 546 }
 547 
 548 sub_t *
 549 templ_top(templ_t *tpl)
 550 {
 551         if (tpl->tpl_len == 0)
 552                 return (NULL);
 553         return (&tpl->tpl_items[tpl->tpl_len - 1]);
 554 }
 555 
 556 boolean_t
 557 templ_empty(const templ_t *tpl)
 558 {
 559         return ((tpl->tpl_len == 0) ? B_TRUE : B_FALSE);
 560 }
 561 
 562 size_t
 563 templ_top_len(const templ_t *tpl)
 564 {
 565         const sub_t *sub = templ_top((templ_t *)tpl);
 566 
 567         return (sub->sub_len);
 568 }
 569 
 570 boolean_t
 571 templ_sub(const templ_t *tpl, size_t idx, name_t *n)
 572 {
 573         const sub_t *sub = templ_top((templ_t *)tpl);
 574 
 575         return (sub_substitute(sub, idx, n));
 576 }
 577 
 578 boolean_t
 579 templ_save(const name_t *n, size_t amt, templ_t *tpl)
 580 {
 581         VERIFY3U(tpl->tpl_len, >, 0);
 582 
 583         sub_t *s = templ_top(tpl);
 584         boolean_t res = B_TRUE;
 585 
 586         /* a bit of a hack -- want an 'empty' entry when saving 0 params */
 587         if (amt == 0) {
 588                 name_t name = { 0 };
 589 
 590                 name_init(&name, tpl->tpl_ops);
 591                 res &= name_add(&name, "", 0, "", 0);
 592                 if (res)
 593                         res &= sub_save(s, &name, 1);
 594                 name_fini(&name);
 595         } else {
 596                 res &= sub_save(s, n, amt);
 597         }
 598 
 599         return (res);
 600 }