int main(void) { Rune r; char *s; int n = 0; Biobuf *i = Bfdopen(0,O_RDONLY); print("enum codepoints {"); while((r=Bgetrune(i))>0 && r != '\n') { s = Brdline(i,'\n'); if(!Blinelen(i)) break; s[Blinelen(i)-1] = '\0'; *s = 'U'; print("%s\n\t%-8s = 0x%X",n?",":"", s,r); n = 1; } print("\n};\n"); Bterm(i); return 0; }
void main(int argc, char **argv) { int p[2], pid, i, j, n, off, npad, prefix; char **av, *q, *r, *tofree, *name; char nambuf[100]; Biobuf *bin, *bout; Type *t; Field *f; quotefmtinstall(); oargc = argc; oargv = argv; av = emalloc((30+argc)*sizeof av[0]); atexit(waitforgcc); n = 0; av[n++] = "gcc"; av[n++] = "-c"; av[n++] = "-fdollars-in-identifiers"; av[n++] = "-S"; // write assembly av[n++] = "-gstabs"; // include stabs info av[n++] = "-o-"; // to stdout av[n++] = "-xc"; // read C ARGBEGIN{ case 'g': lang = &go; pkg = EARGF(usage()); break; case 'c': av[0] = EARGF(usage()); break; case 'f': av[n++] = EARGF(usage()); break; default: usage(); }ARGEND if(argc == 0) av[n++] = "-"; else av[n++] = argv[0]; av[n] = nil; // Run gcc writing assembly and stabs debugging to p[1]. if(pipe(p) < 0) sysfatal("pipe: %r"); pid = fork(); if(pid < 0) sysfatal("fork: %r"); if(pid == 0) { close(p[0]); dup(p[1], 1); if(argc == 0) { exec(av[0], av); fprint(2, "exec gcc: %r\n"); exit(1); } // Some versions of gcc do not accept -S with multiple files. // Run gcc once for each file. close(0); open("/dev/null", OREAD); for(i=0; i<argc; i++) { pid = fork(); if(pid < 0) sysfatal("fork: %r"); if(pid == 0) { av[n-1] = argv[i]; exec(av[0], av); fprint(2, "exec gcc: %r\n"); exit(1); } waitpid(); } exit(0); } close(p[1]); // Read assembly, pulling out .stabs lines. bin = Bfdopen(p[0], OREAD); while((q = Brdstr(bin, '\n', 1)) != nil) { // .stabs "float:t(0,12)=r(0,1);4;0;",128,0,0,0 tofree = q; while(*q == ' ' || *q == '\t') q++; if(strncmp(q, ".stabs", 6) != 0) goto Continue; q += 6; while(*q == ' ' || *q == '\t') q++; if(*q++ != '\"') { Bad: sysfatal("cannot parse .stabs line:\n%s", tofree); } r = strchr(q, '\"'); if(r == nil) goto Bad; *r++ = '\0'; if(*r++ != ',') goto Bad; if(*r < '0' || *r > '9') goto Bad; if(atoi(r) != 128) // stabs kind = local symbol goto Continue; parsestabtype(q); Continue: free(tofree); } Bterm(bin); waitpid(); // Write defs to standard output. bout = Bfdopen(1, OWRITE); fmtinstall('T', lang->typefmt); // Echo original command line in header. Bprint(bout, "//"); for(i=0; i<oargc; i++) Bprint(bout, " %q", oargv[i]); Bprint(bout, "\n"); Bprint(bout, "\n"); Bprint(bout, "// MACHINE GENERATED - DO NOT EDIT.\n"); Bprint(bout, "\n"); if(pkg) Bprint(bout, "package %s\n\n", pkg); // Constants. Bprint(bout, "// Constants\n"); if(ncon > 0) { Bprint(bout, lang->constbegin); for(i=0; i<ncon; i++) Bprint(bout, lang->constfmt, con[i].name, con[i].value); Bprint(bout, lang->constend); } Bprint(bout, "\n"); // Types // push our names down for(i=0; i<ntyp; i++) { t = typ[i]; name = t->name; while(t && t->kind == Typedef) t = t->type; if(t) t->name = name; } Bprint(bout, "// Types\n"); // Have to turn off structure padding in Plan 9 compiler, // mainly because it is more aggressive than gcc tends to be. if(lang == &c) Bprint(bout, "#pragma pack on\n"); for(i=0; i<ntyp; i++) { Bprint(bout, "\n"); t = typ[i]; name = t->name; while(t && t->kind == Typedef) { if(name == nil && t->name != nil) { name = t->name; if(t->printed) break; } t = t->type; } if(name == nil && t->name != nil) { name = t->name; if(t->printed) continue; t->printed = 1; } if(name == nil) { fprint(2, "unknown name for %T", typ[i]); continue; } if(name[0] == '$') name++; npad = 0; off = 0; switch(t->kind) { case 0: fprint(2, "unknown type definition for %s\n", name); break; default: // numeric, array, or pointer case Array: case Ptr: Bprint(bout, "%s %lT\n", lang->typdef, name, t); break; case Union: // In Go, print union as struct with only first element, // padded the rest of the way. Bprint(bout, lang->unionbegin, name, name, name); goto StructBody; case Struct: Bprint(bout, lang->structbegin, name, name, name); StructBody: prefix = 0; if(lang == &go) prefix = prefixlen(t); for(j=0; j<t->nf; j++) { f = &t->f[j]; // padding if(t->kind == Struct || lang == &go) { if(f->offset%8 != 0 || f->size%8 != 0) { fprint(2, "ignoring bitfield %s.%s\n", t->name, f->name); continue; } if(f->offset < off) sysfatal("%s: struct fields went backward", t->name); if(off < f->offset) { Bprint(bout, lang->structpadfmt, npad++, (f->offset - off) / 8); off = f->offset; } off += f->size; } name = f->name; if(cutprefix(name)) name += prefix; if(strcmp(name, "") == 0) { snprint(nambuf, sizeof nambuf, "Pad%d", npad++); name = nambuf; } Bprint(bout, "\t%#lT;\n", name, f->type); if(t->kind == Union && lang == &go) break; } // final padding if(t->kind == Struct || lang == &go) { if(off/8 < t->size) Bprint(bout, lang->structpadfmt, npad++, t->size - off/8); } Bprint(bout, lang->structend); } } if(lang == &c) Bprint(bout, "#pragma pack off\n"); Bterm(bout); exit(0); }