1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * In this mode, we generate forthdebug macros as requested by the input 31*7c478bd9Sstevel@tonic-gate * template, the format of which is given below. 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * These templates have the following elements: 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * 1. Macro creation 36*7c478bd9Sstevel@tonic-gate * 37*7c478bd9Sstevel@tonic-gate * Given the name of a structure, union, or enum type, a forthdebug macro 38*7c478bd9Sstevel@tonic-gate * is created that will dump the members of the type. The type can be 39*7c478bd9Sstevel@tonic-gate * specified as a standalone structure, union, or enum, or it can be 40*7c478bd9Sstevel@tonic-gate * described relative to another structure or union as "type.member". 41*7c478bd9Sstevel@tonic-gate * 42*7c478bd9Sstevel@tonic-gate * By default, all struct members, union members, or enum values, as 43*7c478bd9Sstevel@tonic-gate * appropriate, will be printed. An alternate form allows specific members 44*7c478bd9Sstevel@tonic-gate * of struct or union types to be printed. Both forms must be followed by a 45*7c478bd9Sstevel@tonic-gate * blank line. In the specific-member case, an optional format specifier can 46*7c478bd9Sstevel@tonic-gate * be provided that will be used to dump the contents of the member. 47*7c478bd9Sstevel@tonic-gate * Builtins `d' and `x' can be used to dump the member in decimal or 48*7c478bd9Sstevel@tonic-gate * hexadecimal, respectively. Alternatively, a custom formatter can be 49*7c478bd9Sstevel@tonic-gate * specified. 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * 2. Model-specific sections 52*7c478bd9Sstevel@tonic-gate * 53*7c478bd9Sstevel@tonic-gate * `model_start' / `model_end' pairs function as an #ifdef for the ctfstabs 54*7c478bd9Sstevel@tonic-gate * tool. They take, as an argument, either `ilp32' or `lp64'. If a 64-bit 55*7c478bd9Sstevel@tonic-gate * macro is being generated (if a 64-bit object file is being used), lines 56*7c478bd9Sstevel@tonic-gate * between `lp64' model pairs will be processed, but lines between `ilp32' 57*7c478bd9Sstevel@tonic-gate * pairs will be omitted. The reverse is true for 32-bit macros. 58*7c478bd9Sstevel@tonic-gate * 59*7c478bd9Sstevel@tonic-gate * 3. Literal sections 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * Portions of the input template file enclosed within `forth_start' / 62*7c478bd9Sstevel@tonic-gate * `forth_end' pairs and between `verbatim_begin' / `verbatim_end' pairs 63*7c478bd9Sstevel@tonic-gate * will be copied as-is to the output file. 64*7c478bd9Sstevel@tonic-gate * 65*7c478bd9Sstevel@tonic-gate * 4. Comments 66*7c478bd9Sstevel@tonic-gate * 67*7c478bd9Sstevel@tonic-gate * Lines beginning with backslashes are ignored. 68*7c478bd9Sstevel@tonic-gate * 69*7c478bd9Sstevel@tonic-gate * Example: 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * \ dump the `foo' structure 72*7c478bd9Sstevel@tonic-gate * foo 73*7c478bd9Sstevel@tonic-gate * 74*7c478bd9Sstevel@tonic-gate * \ dump the `a' and `b' members of the `bar' structure. dump member `b' 75*7c478bd9Sstevel@tonic-gate * \ in hexadecimal 76*7c478bd9Sstevel@tonic-gate * bar 77*7c478bd9Sstevel@tonic-gate * a 78*7c478bd9Sstevel@tonic-gate * b x 79*7c478bd9Sstevel@tonic-gate * 80*7c478bd9Sstevel@tonic-gate * \ dump the `big' member of the `baz' structure in 64-bit macros, and 81*7c478bd9Sstevel@tonic-gate * \ the `small' member in 32-bit macros. 82*7c478bd9Sstevel@tonic-gate * baz 83*7c478bd9Sstevel@tonic-gate * model_start lp64 84*7c478bd9Sstevel@tonic-gate * big 85*7c478bd9Sstevel@tonic-gate * model_end 86*7c478bd9Sstevel@tonic-gate * model_start ilp32 87*7c478bd9Sstevel@tonic-gate * small 88*7c478bd9Sstevel@tonic-gate * model_end 89*7c478bd9Sstevel@tonic-gate * 90*7c478bd9Sstevel@tonic-gate * \ copy `literal 1' and `literal 2' to the output file 91*7c478bd9Sstevel@tonic-gate * verbatim_begin 92*7c478bd9Sstevel@tonic-gate * literal 1 93*7c478bd9Sstevel@tonic-gate * verbatim_end 94*7c478bd9Sstevel@tonic-gate * forth_start 95*7c478bd9Sstevel@tonic-gate * literal 2 96*7c478bd9Sstevel@tonic-gate * forth_end 97*7c478bd9Sstevel@tonic-gate * 98*7c478bd9Sstevel@tonic-gate * For a more complex example, see common.fdbg. 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #include <stdio.h> 102*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 103*7c478bd9Sstevel@tonic-gate #include <string.h> 104*7c478bd9Sstevel@tonic-gate #include <ctype.h> 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate #include "ctf_headers.h" 107*7c478bd9Sstevel@tonic-gate #include "ctfstabs.h" 108*7c478bd9Sstevel@tonic-gate #include "forth.h" 109*7c478bd9Sstevel@tonic-gate #include "utils.h" 110*7c478bd9Sstevel@tonic-gate #include "memory.h" 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate char *fth_curtype; /* name of the type being processed */ 113*7c478bd9Sstevel@tonic-gate static fth_type_ops_t *fth_type_ops; /* see forth.h */ 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate static char *fth_model; /* the current macro type - for model_start */ 116*7c478bd9Sstevel@tonic-gate static int fth_ignoring; /* in a non-matching model_start/end pair */ 117*7c478bd9Sstevel@tonic-gate static int fth_copying; /* in a verbatim_* or forth_* pair */ 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate static int 120*7c478bd9Sstevel@tonic-gate fth_init(char *model) 121*7c478bd9Sstevel@tonic-gate { 122*7c478bd9Sstevel@tonic-gate fth_model = model; 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate return (0); 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 128*7c478bd9Sstevel@tonic-gate static int 129*7c478bd9Sstevel@tonic-gate fth_null_header(ctf_id_t tid) 130*7c478bd9Sstevel@tonic-gate { 131*7c478bd9Sstevel@tonic-gate return (0); 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 135*7c478bd9Sstevel@tonic-gate static int 136*7c478bd9Sstevel@tonic-gate fth_null_members(char *memfilter, char *format) 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate return (0); 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate static int 142*7c478bd9Sstevel@tonic-gate fth_null_trailer(void) 143*7c478bd9Sstevel@tonic-gate { 144*7c478bd9Sstevel@tonic-gate return (0); 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate static fth_type_ops_t fth_null_ops = { 148*7c478bd9Sstevel@tonic-gate fth_null_header, 149*7c478bd9Sstevel@tonic-gate fth_null_members, 150*7c478bd9Sstevel@tonic-gate fth_null_trailer 151*7c478bd9Sstevel@tonic-gate }; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 154*7c478bd9Sstevel@tonic-gate static int 155*7c478bd9Sstevel@tonic-gate find_member_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate char *memtofind = arg; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate if (strcmp(memname, memtofind) == 0) 160*7c478bd9Sstevel@tonic-gate return (tid); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate return (0); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* find the tid of a specified member */ 166*7c478bd9Sstevel@tonic-gate static ctf_id_t 167*7c478bd9Sstevel@tonic-gate find_member(ctf_id_t tid, char *memname) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate return (ctf_member_iter(ctf, tid, find_member_cb, memname)); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Begin a macro. 174*7c478bd9Sstevel@tonic-gate * 175*7c478bd9Sstevel@tonic-gate * Once we figure out the type of the thing that we're supposed to dump (struct, 176*7c478bd9Sstevel@tonic-gate * union, or enum), we select the proper type-specific ops-vector for dumping. 177*7c478bd9Sstevel@tonic-gate */ 178*7c478bd9Sstevel@tonic-gate static int 179*7c478bd9Sstevel@tonic-gate fth_section_init(char *fullname) 180*7c478bd9Sstevel@tonic-gate { 181*7c478bd9Sstevel@tonic-gate ctf_id_t ltid = 0, tid; 182*7c478bd9Sstevel@tonic-gate char *curtype, *lpart, *part, *npart; 183*7c478bd9Sstevel@tonic-gate int lkind = 0, kind; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate curtype = xstrdup(fullname); 186*7c478bd9Sstevel@tonic-gate lpart = NULL; 187*7c478bd9Sstevel@tonic-gate part = strtok(fullname, "."); 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate /* 190*7c478bd9Sstevel@tonic-gate * First figure out what sort of type we're looking at. Life would be 191*7c478bd9Sstevel@tonic-gate * simple if we were only going to get type names, but it's not - we 192*7c478bd9Sstevel@tonic-gate * could also get `type.member'. In that case, we need to figure out 193*7c478bd9Sstevel@tonic-gate * (and dump) the type of `member' instead. 194*7c478bd9Sstevel@tonic-gate */ 195*7c478bd9Sstevel@tonic-gate for (;;) { 196*7c478bd9Sstevel@tonic-gate if (lpart == NULL) { 197*7c478bd9Sstevel@tonic-gate /* First part - the struct name */ 198*7c478bd9Sstevel@tonic-gate if ((tid = find_type(part)) == CTF_ERR || 199*7c478bd9Sstevel@tonic-gate (tid = ctf_type_resolve(ctf, tid)) == CTF_ERR || 200*7c478bd9Sstevel@tonic-gate (kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { 201*7c478bd9Sstevel@tonic-gate free(curtype); 202*7c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't find %s: %s", 203*7c478bd9Sstevel@tonic-gate part, ctf_errmsg(ctf_errno(ctf)))); 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate } else { 206*7c478bd9Sstevel@tonic-gate /* Second (or more) part - the member name */ 207*7c478bd9Sstevel@tonic-gate if (lkind != CTF_K_STRUCT && lkind != CTF_K_UNION) { 208*7c478bd9Sstevel@tonic-gate free(curtype); 209*7c478bd9Sstevel@tonic-gate return (parse_warn("%s isn't a struct/union", 210*7c478bd9Sstevel@tonic-gate lpart)); 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate if ((tid = find_member(ltid, part)) <= 0) { 214*7c478bd9Sstevel@tonic-gate free(curtype); 215*7c478bd9Sstevel@tonic-gate return (parse_warn("%s isn't a member of %s", 216*7c478bd9Sstevel@tonic-gate part, lpart)); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { 220*7c478bd9Sstevel@tonic-gate free(curtype); 221*7c478bd9Sstevel@tonic-gate return (parse_warn("Can't get kind for %s", 222*7c478bd9Sstevel@tonic-gate part)); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * Stop if there aren't any more parts. We use `npart' here 228*7c478bd9Sstevel@tonic-gate * because we don't want to clobber part - we need it later. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate if ((npart = strtok(NULL, ".")) == NULL) 231*7c478bd9Sstevel@tonic-gate break; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate lpart = part; 234*7c478bd9Sstevel@tonic-gate ltid = tid; 235*7c478bd9Sstevel@tonic-gate lkind = kind; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate part = npart; 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate /* 241*7c478bd9Sstevel@tonic-gate * Pick the right ops vector for dumping. 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate switch (kind) { 244*7c478bd9Sstevel@tonic-gate case CTF_K_STRUCT: 245*7c478bd9Sstevel@tonic-gate case CTF_K_UNION: 246*7c478bd9Sstevel@tonic-gate fth_type_ops = &fth_struct_ops; 247*7c478bd9Sstevel@tonic-gate break; 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate case CTF_K_ENUM: 250*7c478bd9Sstevel@tonic-gate fth_type_ops = &fth_enum_ops; 251*7c478bd9Sstevel@tonic-gate break; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate default: 254*7c478bd9Sstevel@tonic-gate fth_type_ops = &fth_null_ops; 255*7c478bd9Sstevel@tonic-gate free(curtype); 256*7c478bd9Sstevel@tonic-gate return (parse_warn("%s isn't a struct, union, or enum", part)); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate fth_curtype = curtype; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate return (fth_type_ops->fto_header(tid)); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate static int 265*7c478bd9Sstevel@tonic-gate fth_section_add_member(char *name, char *format) 266*7c478bd9Sstevel@tonic-gate { 267*7c478bd9Sstevel@tonic-gate if (fth_curtype == NULL) 268*7c478bd9Sstevel@tonic-gate return (fth_section_init(name)); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate if (fth_type_ops->fto_members(name, format) < 0) 271*7c478bd9Sstevel@tonic-gate return (-1); 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate return (0); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate static int 277*7c478bd9Sstevel@tonic-gate fth_section_end(void) 278*7c478bd9Sstevel@tonic-gate { 279*7c478bd9Sstevel@tonic-gate if (fth_curtype == NULL) 280*7c478bd9Sstevel@tonic-gate return (0); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate if (fth_type_ops->fto_trailer() < 0) 283*7c478bd9Sstevel@tonic-gate return (-1); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate free(fth_curtype); 286*7c478bd9Sstevel@tonic-gate fth_curtype = NULL; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate return (0); 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate static int 292*7c478bd9Sstevel@tonic-gate fth_process_line(char *line) 293*7c478bd9Sstevel@tonic-gate { 294*7c478bd9Sstevel@tonic-gate char *format = NULL; 295*7c478bd9Sstevel@tonic-gate char *word, *name, *c; 296*7c478bd9Sstevel@tonic-gate int nblank = 0; 297*7c478bd9Sstevel@tonic-gate int n; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate if (strlen(line) == 0) { 300*7c478bd9Sstevel@tonic-gate if (fth_section_end() < 0) 301*7c478bd9Sstevel@tonic-gate return (-1); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if (fth_copying == 1 || nblank++ == 1) 304*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "\n"); 305*7c478bd9Sstevel@tonic-gate return (0); 306*7c478bd9Sstevel@tonic-gate } else 307*7c478bd9Sstevel@tonic-gate nblank = 0; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* skip comments */ 310*7c478bd9Sstevel@tonic-gate if (line[0] == '\\') 311*7c478bd9Sstevel@tonic-gate return (0); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate if (strcmp(line, "model_end") == 0) { 314*7c478bd9Sstevel@tonic-gate fth_ignoring = 0; 315*7c478bd9Sstevel@tonic-gate return (0); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (fth_ignoring == 1) 319*7c478bd9Sstevel@tonic-gate return (0); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate word = "model_start "; 322*7c478bd9Sstevel@tonic-gate if (strncmp(line, word, strlen(word)) == 0) { 323*7c478bd9Sstevel@tonic-gate for (c = line + strlen(word); isspace(*c); c++); 324*7c478bd9Sstevel@tonic-gate if (strlen(c) == strlen(fth_model) && 325*7c478bd9Sstevel@tonic-gate strncmp(c, fth_model, strlen(fth_model)) == 0) 326*7c478bd9Sstevel@tonic-gate /* EMPTY - match */; 327*7c478bd9Sstevel@tonic-gate else 328*7c478bd9Sstevel@tonic-gate fth_ignoring = 1; 329*7c478bd9Sstevel@tonic-gate return (0); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate if (strcmp(line, "verbatim_end") == 0 || 333*7c478bd9Sstevel@tonic-gate strcmp(line, "forth_end") == 0) { 334*7c478bd9Sstevel@tonic-gate char *start = (strcmp(line, "verbatim_end") == 0 ? 335*7c478bd9Sstevel@tonic-gate "verbatim_begin" : "forth_start"); 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate if (fth_copying == 0) { 338*7c478bd9Sstevel@tonic-gate (void) parse_warn("Found %s without matching %s", 339*7c478bd9Sstevel@tonic-gate line, start); 340*7c478bd9Sstevel@tonic-gate if (fth_curtype != NULL) 341*7c478bd9Sstevel@tonic-gate (void) fth_section_end(); 342*7c478bd9Sstevel@tonic-gate return (-1); 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate fth_copying = 0; 345*7c478bd9Sstevel@tonic-gate return (0); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate if (fth_copying == 1) { 349*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s\n", line); 350*7c478bd9Sstevel@tonic-gate return (0); 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate if (strcmp(line, "verbatim_begin") == 0 || 354*7c478bd9Sstevel@tonic-gate strcmp(line, "forth_start") == 0) { 355*7c478bd9Sstevel@tonic-gate if (fth_curtype != NULL) { 356*7c478bd9Sstevel@tonic-gate (void) parse_warn("Expected blank line between %s " 357*7c478bd9Sstevel@tonic-gate "macro and %s", fth_curtype, line); 358*7c478bd9Sstevel@tonic-gate return (fth_section_end()); 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate fth_copying = 1; 362*7c478bd9Sstevel@tonic-gate return (0); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate for (n = 1, word = strtok(line, " \t"); word != NULL; 366*7c478bd9Sstevel@tonic-gate word = strtok(NULL, " \t"), n++) { 367*7c478bd9Sstevel@tonic-gate if (n == 1) 368*7c478bd9Sstevel@tonic-gate name = word; 369*7c478bd9Sstevel@tonic-gate else if (n == 2) 370*7c478bd9Sstevel@tonic-gate format = word; 371*7c478bd9Sstevel@tonic-gate else 372*7c478bd9Sstevel@tonic-gate (void) parse_warn("Too many words"); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate return (fth_section_add_member(name, format)); 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate static int 379*7c478bd9Sstevel@tonic-gate fth_fini(void) 380*7c478bd9Sstevel@tonic-gate { 381*7c478bd9Sstevel@tonic-gate return (fth_section_end()); 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate proc_ops_t fth_ops = { 385*7c478bd9Sstevel@tonic-gate fth_init, 386*7c478bd9Sstevel@tonic-gate fth_process_line, 387*7c478bd9Sstevel@tonic-gate fth_fini 388*7c478bd9Sstevel@tonic-gate }; 389