]> Cypherpunks repositories - gostls13.git/commitdiff
gopack: add P flag to remove prefix from filename information
authorRuss Cox <rsc@golang.org>
Thu, 31 Mar 2011 02:19:02 +0000 (22:19 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 31 Mar 2011 02:19:02 +0000 (22:19 -0400)
R=r, r2
CC=golang-dev
https://golang.org/cl/4307047

src/cmd/gopack/ar.c
src/cmd/gopack/doc.go

index 4c241358d4687530361c97d048ae9af6d5f65d4d..8f0cfbf8045672da7c78305d8fb1ed151db3cec2 100644 (file)
@@ -41,6 +41,7 @@
 #include <libc.h>
 #include <bio.h>
 #include <mach.h>
+#include "../../libmach/obj.h"
 #include <ar.h>
 
 #undef select
@@ -123,6 +124,7 @@ int gflag;
 int    oflag;
 int    uflag;
 int    vflag;
+int    Pflag;  /* remove leading file prefix */
 int    Sflag;  /* force mark Go package as safe */
 
 int    errors;
@@ -141,6 +143,7 @@ char        poname[ARNAMESIZE+1];           /* name of pivot member */
 char   *file;                          /* current file or member being worked on */
 Biobuf bout;
 Biobuf bar;
+char   *prefix;
 
 void   arcopy(Biobuf*, Arfile*, Armember*);
 int    arcreate(char*);
@@ -149,7 +152,7 @@ void        arinsert(Arfile*, Armember*);
 void   *armalloc(int);
 char *arstrdup(char*);
 void   armove(Biobuf*, Arfile*, Armember*);
-void   arread(Biobuf*, Armember*, int);
+void   arread(Biobuf*, Armember*);
 void   arstream(int, Arfile*);
 int    arwrite(int, Armember*);
 int    bamatch(char*, char*);
@@ -179,6 +182,7 @@ void        trim(char*, char*, int);
 void   usage(void);
 void   wrerr(void);
 void   wrsym(Biobuf*, long, Arsymref*);
+int    arread_cutprefix(Biobuf*, Armember*);
 
 void   rcmd(char*, int, char**);               /* command processing */
 void   dcmd(char*, int, char**);
@@ -220,6 +224,7 @@ main(int argc, char *argv[])
                case 'v':       vflag = 1;      break;
                case 'x':       setcom(xcmd);   break;
                case 'S':       Sflag = 1;  break;
+               case 'P':       Pflag = 1;  break;
                default:
                        fprint(2, "gopack: bad option `%c'\n", *cp);
                        exits("error");
@@ -236,6 +241,15 @@ main(int argc, char *argv[])
                if(argc < 3)
                        usage();
        }
+       if(Pflag) {
+               if(argc < 4) {
+                       fprint(2, "gopack: P flag requires prefix argument\n");
+                       usage();
+               }
+               prefix = argv[2];
+               argv++;
+               argc--;
+       }
        if(comfun == 0) {
                if(uflag == 0) {
                        fprint(2, "gopack: one of [%s] must be specified\n", man);
@@ -313,7 +327,16 @@ rcmd(char *arname, int count, char **files)
                        skip(&bar, bp->size);
                        continue;
                }
-               if (count && !match(count, files)) {
+               /*
+                * the plan 9 ar treats count == 0 as equivalent
+                * to listing all the archive's files on the command line:
+                * it will try to open every file name in the archive
+                * and copy that file into the archive if it exists.
+                * for go we disable that behavior, because we use
+                * r with no files to make changes to the archive itself,
+                * using the S or P flags.
+                */
+               if (!match(count, files)) {
                        scanobj(&bar, ap, bp->size);
                        arcopy(&bar, ap, bp);
                        continue;
@@ -972,7 +995,7 @@ phaseerr(int offset)
 void
 usage(void)
 {
-       fprint(2, "usage: gopack [%s][%s] archive files ...\n", opt, man);
+       fprint(2, "usage: gopack [%s][%s][P prefix] archive files ...\n", opt, man);
        exits("error");
 }
 
@@ -1012,12 +1035,14 @@ armove(Biobuf *b, Arfile *ap, Armember *bp)
 {
        char *cp;
        Dir *d;
+       vlong n;
 
        d = dirfstat(Bfildes(b));
        if (d == nil) {
                fprint(2, "gopack: cannot stat %s\n", file);
                return;
        }
+
        trim(file, bp->hdr.name, sizeof(bp->hdr.name));
        for (cp = strchr(bp->hdr.name, 0);              /* blank pad on right */
                cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
@@ -1029,12 +1054,13 @@ armove(Biobuf *b, Arfile *ap, Armember *bp)
        sprint(bp->hdr.size, "%-10lld", d->length);
        strncpy(bp->hdr.fmag, ARFMAG, 2);
        bp->size = d->length;
-       arread(b, bp, bp->size);
-       if (d->length&0x01)
-               d->length++;
+       arread(b, bp);
+       n = bp->size;
+       if (n&1)
+               n++;
        if (ap) {
                arinsert(ap, bp);
-               ap->size += d->length+SAR_HDR;
+               ap->size += n+SAR_HDR;
        }
        free(d);
 }
@@ -1047,10 +1073,10 @@ arcopy(Biobuf *b, Arfile *ap, Armember *bp)
 {
        long n;
 
+       arread(b, bp);
        n = bp->size;
        if (n & 01)
                n++;
-       arread(b, bp, n);
        if (ap) {
                arinsert(ap, bp);
                ap->size += n+SAR_HDR;
@@ -1316,7 +1342,8 @@ longt(Armember *bp)
        Bprint(&bout, "%7ld", bp->size);
        date = bp->date;
        cp = ctime(&date);
-       Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
+       /* using unix ctime, not plan 9 time, so cp+20 for year, not cp+24 */
+       Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+20);
 }
 
 int    m1[] = { 1, ROWN, 'r', '-' };
@@ -1378,17 +1405,29 @@ newmember(void)                 /* allocate a member buffer */
 }
 
 void
-arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */
+arread(Biobuf *b, Armember *bp)        /* read an image into a member buffer */
 {
        int i;
+       vlong off;
 
-       bp->member = armalloc(n);
-       i = Bread(b, bp->member, n);
+       bp->member = armalloc(bp->size);
+       
+       // If P flag is set, let arread_cutprefix try.
+       // If it succeeds, we're done.  If not, fall back
+       // to a direct copy.
+       off = Boffset(b);
+       if(Pflag && arread_cutprefix(b, bp))
+               return;
+       Bseek(b, off, 0);
+
+       i = Bread(b, bp->member, bp->size);
        if (i < 0) {
                free(bp->member);
                bp->member = 0;
                rderr();
        }
+       if(bp->size&1)
+               Bgetc(b);
 }
 
 /*
@@ -1551,3 +1590,109 @@ arstrdup(char *s)
 }
 
 
+/*
+ *     Parts of libmach we're not supposed
+ *     to look at but need for arread_cutprefix.
+ */
+extern int _read5(Biobuf*, Prog*);
+extern int _read6(Biobuf*, Prog*);
+extern int _read8(Biobuf*, Prog*);
+int (*reader[256])(Biobuf*, Prog*) = {
+       [ObjArm] = _read5,
+       [ObjAmd64] = _read6,
+       [Obj386] = _read8,
+};
+
+/*
+ *     copy b into bp->member but rewrite object
+ *     during copy to drop prefix from all file names.
+ *     return 1 if b was recognized as an object file
+ *     and copied successfully, 0 otherwise.
+ */
+int
+arread_cutprefix(Biobuf *b, Armember *bp)
+{
+       vlong offset, o, end;
+       int n, t;
+       int (*rd)(Biobuf*, Prog*);
+       char *w, *inprefix;
+       Prog p;
+       
+       offset = Boffset(b);
+       end = offset + bp->size;
+       t = objtype(b, nil);
+       if(t < 0)
+               return 0;
+       if((rd = reader[t]) == nil)
+               return 0;
+       
+       // copy header
+       w = bp->member;
+       n = Boffset(b) - offset;
+       Bseek(b, -n, 1);
+       if(Bread(b, w, n) != n)
+               return 0;
+       offset += n;
+       w += n;
+       
+       // read object file one pseudo-instruction at a time,
+       // eliding the file name instructions that refer to
+       // the prefix.
+       memset(&p, 0, sizeof p);
+       inprefix = nil;
+       while(Boffset(b) < end && rd(b, &p)) {
+               if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
+                       // part of a file path.
+                       // we'll keep continuing (skipping the copy)
+                       // around the loop until either we get to a
+                       // name piece that should be kept or we see
+                       // the whole prefix.
+
+                       if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') {
+                               // leading /
+                               inprefix = prefix+1;
+                       } else if(inprefix != nil) {
+                               // handle subsequent elements
+                               n = strlen(p.id+1);
+                               if(strncmp(p.id+1, inprefix, n) == 0 && (inprefix[n] == '/' || inprefix[n] == '\0')) {
+                                       inprefix += n;
+                                       if(inprefix[0] == '/')
+                                               inprefix++;
+                               }
+                       }
+                       
+                       if(inprefix && inprefix[0] == '\0') {
+                               // reached end of prefix.
+                               // if we another path element follows,
+                               // nudge the offset to skip over the prefix we saw.
+                               // if not, leave offset alone, to emit the whole name.
+                               // additional name elements will not be skipped
+                               // because inprefix is now nil and we won't see another
+                               // leading / in this name.
+                               inprefix = nil;
+                               o = Boffset(b);
+                               if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
+                                       print("skip %lld-%lld\n", offset, o);
+                                       offset = o;
+                               }
+                       }
+               }
+
+               // copy instructions
+               if(!inprefix) {
+                       n = Boffset(b) - offset;
+                       Bseek(b, -n, 1);
+                       if(Bread(b, w, n) != n)
+                               return 0;
+                       offset += n;
+                       w += n;
+               }
+       }
+       bp->size = w - (char*)bp->member;
+       sprint(bp->hdr.size, "%-10lld", (vlong)bp->size);
+       strncpy(bp->hdr.fmag, ARFMAG, 2);
+       Bseek(b, end, 0);
+       if(Boffset(b)&1)
+               Bgetc(b);
+       return 1;
+}
index 08711e72e179af223447690c955dfe477629d638..1551a275fd41c7966f7e18fde305a3ffb176a193 100644 (file)
@@ -12,12 +12,15 @@ It adds a special Go-specific section __.PKGDEF that collects all the
 Go type information from the files in the archive; that section is
 used by the compiler when importing the package during compilation.
 
-Usage: gopack [uvnbailogS][mrxtdpq] archive files ...
+Usage: gopack [uvnbailogS][mrxtdpq][P prefix] archive files ...
 
 The new option 'g' causes gopack to maintain the __.PKGDEF section
 as files are added to the archive.
 
 The new option 'S' forces gopack to mark the archive as safe.
 
+The new option 'P' causes gopack to remove the given prefix
+from file names in the line number information in object files
+that are already stored in or added to the archive.
 */
 package documentation