1
0
mirror of https://github.com/golang/go synced 2024-11-21 14:04:41 -07:00

gopack: simplify go metadata code

There's only one Go object file per package now,
so there's no need to parse the metadata and merge
metadata from multiple files.  Just save the original
and use it as __.PKGDEF verbatim.

R=r
CC=golang-dev
https://golang.org/cl/1647042
This commit is contained in:
Russ Cox 2010-06-11 15:29:19 -07:00
parent d20ad1c75a
commit ee0bca35a4

View File

@ -630,7 +630,7 @@ scanobj(Biobuf *b, Arfile *ap, long size)
}
/*
* does line contain substring (length-limited)
* does line contain substring (length-limited)
*/
int
strstrn(char *line, int len, char *sub)
@ -646,7 +646,26 @@ strstrn(char *line, int len, char *sub)
}
/*
* Extract the package definition data from an object file
* package import data
*/
char* pkgname;
char* importblock;
void
getpkgdef(char **datap, int *lenp)
{
if(pkgname == nil) {
pkgname = "__emptyarchive__";
importblock = "";
}
*datap = smprint("import\n$$\npackage %s\n%s\n$$\n", pkgname, importblock);
*lenp = strlen(*datap);
}
/*
* extract the package definition data from an object file.
* there can be only one.
*/
void
scanpkg(Biobuf *b, long size)
@ -702,6 +721,13 @@ foundstart:
pkg++;
if(strncmp(pkg, "package ", 8) != 0)
goto bad;
pkg += 8;
data = pkg;
while(*pkg != ' ' && *pkg != '\n' && *pkg != '\0')
pkg++;
pkgname = armalloc(pkg - data + 1);
memmove(pkgname, data, pkg - data);
pkgname[pkg-data] = '\0';
start = Boffset(b); // after package statement
first = 0;
continue;
@ -719,24 +745,21 @@ foundend:
return;
if (end == 0)
goto bad;
if (pkgstmt == nil) {
/* this is the first package */
pkgstmt = arstrdup(pkg);
} else {
if (strcmp(pkg, pkgstmt) != 0) {
fprint(2, "gopack: inconsistent package name\n");
return;
}
if(importblock != nil) {
fprint(2, "gopack: multiple Go object files\n");
errors++;
return;
}
pkgsize = end-start;
data = armalloc(pkgsize);
data = armalloc(end - start + 1);
Bseek(b, start, 0);
if (Bread(b, data, pkgsize) != pkgsize) {
fprint(2, "gopack: error reading package import section in %s\n", file);
errors++;
return;
}
loadpkgdata(data, pkgsize);
data[end-start] = '\0';
importblock = data;
}
/*
@ -1464,304 +1487,3 @@ arstrdup(char *s)
}
/*
* package import data
*/
typedef struct Import Import;
struct Import
{
Import *hash; // next in hash table
char *prefix; // "type", "var", "func", "const"
char *name;
char *def;
char *file;
};
enum {
NIHASH = 1024
};
Import *ihash[NIHASH];
int nimport;
Import *
ilookup(char *name)
{
int h;
Import *x;
h = hashstr(name) % NIHASH;
for(x=ihash[h]; x; x=x->hash)
if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
return x;
x = armalloc(sizeof *x);
x->name = name;
x->hash = ihash[h];
ihash[h] = x;
nimport++;
return x;
}
int parsemethod(char**, char*, char**);
int parsepkgdata(char**, char*, char**, char**, char**);
void
loadpkgdata(char *data, int len)
{
char *p, *ep, *prefix, *name, *def;
Import *x;
p = data;
ep = data + len;
while(parsepkgdata(&p, ep, &prefix, &name, &def) > 0) {
if(strcmp(prefix, "import") == 0) {
// backwards from the rest: def is unique, name is not.
x = ilookup(def);
if(x->prefix == nil) {
x->prefix = prefix;
x->def = name;
x->file = file;
} else if(strcmp(x->def, name) != 0) {
fprint(2, "gopack: conflicting package names for %s\n", def);
fprint(2, "%s:\t%s\n", x->file, x->def);
fprint(2, "%s:\t%s\n", file, name);
errors++;
}
continue;
}
x = ilookup(name);
if(x->prefix == nil) {
x->prefix = prefix;
x->def = def;
x->file = file;
} else if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "gopack: conflicting definitions for %s\n", name);
fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
errors++;
} else if(strcmp(x->def, def) != 0) {
fprint(2, "gopack: conflicting definitions for %s\n", name);
fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
errors++;
}
}
}
int
parsepkgdata(char **pp, char *ep, char **prefixp, char **namep, char **defp)
{
char *p, *prefix, *name, *def, *edef, *meth;
int n;
// skip white space
p = *pp;
while(p < ep && (*p == ' ' || *p == '\t'))
p++;
if(p == ep)
return 0;
// prefix: (var|type|func|const)
prefix = p;
prefix = p;
if(p + 7 > ep)
return -1;
if(strncmp(p, "var ", 4) == 0)
p += 4;
else if(strncmp(p, "type ", 5) == 0)
p += 5;
else if(strncmp(p, "func ", 5) == 0)
p += 5;
else if(strncmp(p, "const ", 6) == 0)
p += 6;
else if(strncmp(p, "import ", 7) == 0)
p += 7;
else {
fprint(2, "gopack: confused in pkg data near <<%.20s>>\n", p);
errors++;
return -1;
}
p[-1] = '\0';
// name: a.b followed by space
name = p;
while(p < ep && *p != ' ')
p++;
if(p >= ep)
return -1;
*p++ = '\0';
// def: free form to new line
def = p;
while(p < ep && *p != '\n')
p++;
if(p >= ep)
return -1;
edef = p;
*p++ = '\0';
// include methods on successive lines in def of named type
while(parsemethod(&p, ep, &meth) > 0) {
*edef++ = '\n'; // overwrites '\0'
if(edef+1 > meth) {
// We want to indent methods with a single \t.
// 6g puts at least one char of indent before all method defs,
// so there will be room for the \t. If the method def wasn't
// indented we could do something more complicated,
// but for now just diagnose the problem and assume
// 6g will keep indenting for us.
fprint(2, "gopack: %s: expected methods to be indented %p %p %.10s\n", file, edef, meth, meth);
errors++;
return -1;
}
*edef++ = '\t';
n = strlen(meth);
memmove(edef, meth, n);
edef += n;
}
// done
*pp = p;
*prefixp = prefix;
*namep = name;
*defp = def;
return 1;
}
int
parsemethod(char **pp, char *ep, char **methp)
{
char *p;
// skip white space
p = *pp;
while(p < ep && (*p == ' ' || *p == '\t'))
p++;
if(p == ep)
return 0;
// if it says "func (", it's a method
if(p + 6 >= ep || strncmp(p, "func (", 6) != 0)
return 0;
// definition to end of line
*methp = p;
while(p < ep && *p != '\n')
p++;
if(p >= ep) {
fprint(2, "gopack: lost end of line in method definition\n");
*pp = ep;
return -1;
}
*p++ = '\0';
*pp = p;
return 1;
}
int
importcmp(const void *va, const void *vb)
{
Import *a, *b;
int i;
a = *(Import**)va;
b = *(Import**)vb;
i = strcmp(a->prefix, b->prefix);
if(i != 0) {
// rewrite so "type" comes first
if(strcmp(a->prefix, "type") == 0)
return -1;
if(strcmp(b->prefix, "type") == 0)
return 1;
return i;
}
return strcmp(a->name, b->name);
}
char*
strappend(char *s, char *t)
{
int n;
n = strlen(t);
memmove(s, t, n);
return s+n;
}
void
getpkgdef(char **datap, int *lenp)
{
int i, j, len;
char *data, *p;
Import **all, *x;
if(pkgstmt == nil) {
// Write out non-empty, parseable __.PKGDEF,
// so that import of an empty archive works.
*datap = "import\n$$\npackage __emptypackage__\n$$\n";
*lenp = strlen(*datap);
return;
}
// make a list of all the exports and count string sizes
all = armalloc(nimport*sizeof all[0]);
j = 0;
len = 7 + 3 + strlen(pkgstmt) + 1; // import\n$$\npkgstmt\n
for(i=0; i<NIHASH; i++) {
for(x=ihash[i]; x; x=x->hash) {
all[j++] = x;
len += strlen(x->prefix) + 1
+ strlen(x->name) + 1
+ strlen(x->def) + 1;
}
}
if(j != nimport) {
fprint(2, "gopack: import count mismatch (internal error)\n");
exits("oops");
}
len += 3; // $$\n
// sort exports (unnecessary but nicer to look at)
qsort(all, nimport, sizeof all[0], importcmp);
// print them into buffer
data = armalloc(len);
// import\n
// $$\n
// pkgstmt\n
p = data;
p = strappend(p, "import\n$$\n");
p = strappend(p, pkgstmt);
p = strappend(p, "\n");
for(i=0; i<nimport; i++) {
x = all[i];
if(strcmp(x->prefix, "import") == 0) {
// prefix def name\n
p = strappend(p, x->prefix);
p = strappend(p, " ");
p = strappend(p, x->def);
p = strappend(p, " ");
p = strappend(p, x->name);
p = strappend(p, "\n");
continue;
}
// prefix name def\n
p = strappend(p, x->prefix);
p = strappend(p, " ");
p = strappend(p, x->name);
p = strappend(p, " ");
p = strappend(p, x->def);
p = strappend(p, "\n");
}
p = strappend(p, "$$\n");
if(p != data+len) {
fprint(2, "gopack: internal math error\n");
exits("oops");
}
*datap = data;
*lenp = len;
}