{"thread":{"id":"9753","subject":"strbuf API","startedAt":"2007-09-02T22:42:13Z","lastAt":"2007-09-19T08:36:57Z","messageCount":90,"participants":["Pierre Habouzit","Johan Herland","Matthieu Moy","Junio C Hamano","Johannes Schindelin","Miles Bader","Andreas Ericsson","Wincent Colaiuta","René Scharfe","Jeff King","David Kastrup","Johannes Sixt","Kristian Høgsberg"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"52268","messageId":"20070902224213.GB431@artemis.corp","threadId":"9753","inReplyTo":null,"subject":"strbuf API","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-02T22:42:13Z","receivedAt":"2007-09-02T22:42:13Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"\n  I read the recent thread Timo Sirainen raised about string APIs in\ngit. ANd I went read the strbuf.[hc] module.\n\n  I believe that the choice made in that module are wrong and could be\nmade better. I actually use to work with a string buffer API (that\ninterested readers can look at on [0]), that work almost the same\n(except for the eof flag, but it's trivial to keep), but have\ntwo significant differences:\n\n  First, and that's the most important one: the buffer is always NUL\nterminated, after its official \"len\". That means, in terms of strbuf\nAPI, that \"alloc\" is always greater or equal to len+1 to be able to\nstore the ending NUL[1]. The advantages are obvious: you can pass the\nbuffer to any legacy C string function without any fear of read\noverflow.  strtol comes to mind, and atm, git has to explicitely use\nstrbuf_end to put that ending nul to be able to call legacy\napplications. But once done, the NUL is accounted into the string (aka\nit's in \"len\") which makes it a non C-string (I mean you cannot append\nany more data in it anymore). So current implementations tries to\nworkaround an issue (the non systematical NUL-termination) but IMHO the\nwrong way.\n\n  The other shortcoming is that you cannot tell the buffer \"Hey, it's\nvery likely that you'll end up being _that_ long. That's why, in some\nparts of the code (see write_tar_entry in archive-tar.c e.g.) the\nprogrammer actually messes with the buffer allocation, outside from the\nstrbuf module, which makes it well, useless. In my API, I have a\n\"buffer_ensure\" call, that is supposed to do that: \"please ensure that\nthis buffer still has _this_ amount of free and allocated space to put\nmore data\".\n\n\n  So my question is, do people think I raise a valid point, and would\npatches that would refactor the strbuf module to have those functions,\nand would fix the code that uses strbuf's to interact properly, be\naccepted ?\n\n  Also, the efficiency of the buffer module API I use has a lot to do\nwith the fact that copying functions, and length tests are inlined in\nthe .h, so that the compiler can optimize the ones it already tested 10\ncalls before. I'm not sure if this is frowned upon or if it makes sense.\n\n\n  [0] http://git.madism.org/?p=pfixtools.git;a=blob;f=buffer.h;hb=HEAD\n      http://git.madism.org/?p=pfixtools.git;a=blob;f=buffer.c;hb=HEAD\n\n  [1] Of course, ensuring the NUL-termination has a cost, though it's\n      often benign, and for performance-critical places where characters\n      are copied one by one, it's always possible to use an \"unsafe\"\n      addch (that would not maintain the invariant), and then call an\n      equivalent of strbuf_end (that would not append a \\0 like it does\n      now, but just would fix the invariant that for any strbuf,\n      buf->buf[buf->len] == '\\0') explicitely. For places where the\n      invariant generate negligible cost (like concatenating two paths\n      parts with a middle '/' e.g.) then we gain safety without even\n      having to think about it.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52300","messageId":"200709030743.44188.johan@herland.net","threadId":"9753","inReplyTo":"20070902224213.GB431@artemis.corp","subject":"Re: strbuf API","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2007-09-03T05:43:44Z","receivedAt":"2007-09-03T05:43:44Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Monday 03 September 2007, Pierre Habouzit wrote:\n> \n>   I read the recent thread Timo Sirainen raised about string APIs in\n> git. ANd I went read the strbuf.[hc] module.\n> \n>   I believe that the choice made in that module are wrong and could be\n> made better. I actually use to work with a string buffer API (that\n> interested readers can look at on [0]), that work almost the same\n> (except for the eof flag, but it's trivial to keep), but have\n> two significant differences:\n> \n>   First, and that's the most important one: the buffer is always NUL\n> terminated, after its official \"len\". That means, in terms of strbuf\n> API, that \"alloc\" is always greater or equal to len+1 to be able to\n> store the ending NUL[1]. The advantages are obvious: you can pass the\n> buffer to any legacy C string function without any fear of read\n> overflow.  strtol comes to mind, and atm, git has to explicitely use\n> strbuf_end to put that ending nul to be able to call legacy\n> applications. But once done, the NUL is accounted into the string (aka\n> it's in \"len\") which makes it a non C-string (I mean you cannot append\n> any more data in it anymore). So current implementations tries to\n> workaround an issue (the non systematical NUL-termination) but IMHO the\n> wrong way.\n> \n>   The other shortcoming is that you cannot tell the buffer \"Hey, it's\n> very likely that you'll end up being _that_ long. That's why, in some\n> parts of the code (see write_tar_entry in archive-tar.c e.g.) the\n> programmer actually messes with the buffer allocation, outside from the\n> strbuf module, which makes it well, useless. In my API, I have a\n> \"buffer_ensure\" call, that is supposed to do that: \"please ensure that\n> this buffer still has _this_ amount of free and allocated space to put\n> more data\".\n> \n> \n>   So my question is, do people think I raise a valid point\n\nYes.\n\n>   , and would \n> patches that would refactor the strbuf module to have those functions,\n> and would fix the code that uses strbuf's to interact properly, be\n> accepted ?\n\nI don't know. Keep in mind that there is a parallel process (cf. the \ncontinuation of the \"Buffer overflows\" thread) to evaluate the Bstring \nlibrary ( http://bstring.sourceforge.net/ ), and possibly substitute that \nfor the strbuf \"module\".\n\nI wouldn't want the work done by you or others to be wasted (depending on \nwhich solution wins out in the end), so I suggest you take a look at \nbstring and offer up arguments why your solution would be better for git.\n\n>   Also, the efficiency of the buffer module API I use has a lot to do\n> with the fact that copying functions, and length tests are inlined in\n> the .h, so that the compiler can optimize the ones it already tested 10\n> calls before. I'm not sure if this is frowned upon or if it makes sense.\n> \n> \n>   [0] http://git.madism.org/?p=pfixtools.git;a=blob;f=buffer.h;hb=HEAD\n>       http://git.madism.org/?p=pfixtools.git;a=blob;f=buffer.c;hb=HEAD\n> \n>   [1] Of course, ensuring the NUL-termination has a cost, though it's\n>       often benign, and for performance-critical places where characters\n>       are copied one by one, it's always possible to use an \"unsafe\"\n>       addch (that would not maintain the invariant), and then call an\n>       equivalent of strbuf_end (that would not append a \\0 like it does\n>       now, but just would fix the invariant that for any strbuf,\n>       buf->buf[buf->len] == '\\0') explicitely. For places where the\n>       invariant generate negligible cost (like concatenating two paths\n>       parts with a middle '/' e.g.) then we gain safety without even\n>       having to think about it.\n\nAll the points you raise are valid, but please have in mind that all \nprogrammers write their own string library at some point. (Writing a string \nlibrary is right up there with \"discovering why 'goto' is bad\" and \"2nd \nsystem syndrome\" on the top list of rites of passage all programmers (need \nto) go through. I'm guessing 99% of the people on this list have written \ntheir own string library. Why not 100%? Well, Linus have obviously not, \nelse we'd be using his already... ;)\n\nI'd like to know how your solution compare with the alternatives (in this \ncase bstring): What's the performance compared to bstring? How much thought \nhas been given to the usability of the API? What functionality is covered \n(compared to bstring)? In short: Why is your alternative the best for git?\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"52321","messageId":"vpqk5r8m9nz.fsf@bauges.imag.fr","threadId":"9753","inReplyTo":"20070902224213.GB431@artemis.corp","subject":"Re: strbuf API","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2007-09-03T08:32:16Z","receivedAt":"2007-09-03T08:32:16Z","isPatch":false,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   First, and that's the most important one: the buffer is always NUL\n> terminated, after its official \"len\". That means, in terms of strbuf\n> API, that \"alloc\" is always greater or equal to len+1 to be able to\n> store the ending NUL[1]. The advantages are obvious: you can pass the\n> buffer to any legacy C string function without any fear of read\n> overflow.\n\nNo overflow, but it's still potentially dangerous: if your strbuf\ncontains a '\\0', you can't use any standard C string function.\n\nFor example, it would be very tempting to compare files with\n\"strcmp(buf1, buf2)\", but that would just fail silently when the file\ncontains a '\\0' byte.\n\nI don't have a perfect solution, but having something explicit to say\n\"hey, I'm going to use a legacy C function\" doesn't sound like a bad\nidea.\n\n>   The other shortcoming is that you cannot tell the buffer \"Hey, it's\n> very likely that you'll end up being _that_ long.\n\n100% ACK on this point.\n\n-- \nMatthieu\n"},{"id":"52322","messageId":"20070903084610.GA21759@artemis.corp","threadId":"9753","inReplyTo":"200709030743.44188.johan@herland.net","subject":"Re: strbuf API","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-03T08:46:10Z","receivedAt":"2007-09-03T08:46:10Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Mon, Sep 03, 2007 at 05:43:44AM +0000, Johan Herland wrote:\n> On Monday 03 September 2007, Pierre Habouzit wrote:\n> >   , and would \n> > patches that would refactor the strbuf module to have those functions,\n> > and would fix the code that uses strbuf's to interact properly, be\n> > accepted ?\n> \n> I don't know. Keep in mind that there is a parallel process (cf. the \n> continuation of the \"Buffer overflows\" thread) to evaluate the Bstring \n> library ( http://bstring.sourceforge.net/ ), and possibly substitute that \n> for the strbuf \"module\".\n>\n> I wouldn't want the work done by you or others to be wasted (depending on \n> which solution wins out in the end), so I suggest you take a look at \n> bstring and offer up arguments why your solution would be better for git.\n\n  Oh I completely missed that the thread was still alive.\n\n> I'd like to know how your solution compare with the alternatives (in this \n> case bstring): What's the performance compared to bstring? How much thought \n> has been given to the usability of the API? What functionality is covered \n> (compared to bstring)? In short: Why is your alternative the best for git?\n\n  Well, technically, I don't mind, I wasn't really pushing this or this\nimplementation. I had a look at bstring, I dislike the code that looks\npretty ugly, but they almost took the same decisions, so if the\nconsensus is that bstring gives flexibility, so be it.\n\n  For the record, I dislike the fact that bstring pullutes the b*\nnamespace, whereas it should use bstr as a prefix everywhere, and some\nfunctions (like bstrcpy, that should definitely be named bstrdup) are\nreally named the _wrong_ way: you can dislike legacy C string APIs all\nthe way you want, if you name a function from your foostr library\nfoostrbar, it better behave the way strbar does in the legacy C API. In\nthe legacy C, strcpy clobbers the destination, here there is no\ndestination as bstrcpy is definitely a strdup operation. I only had a\nquick look, and maybe it was the sole of the kind, but ... well.\n\n  I also dislike the fact that there is no inline version of the\nfunction that appends C strings, because it means that when you append a\nconstant string into a bstr, you'll need to write:\n\n  bstrcat(bstr, \"foo\", sizeof(\"foo\") - 1) or bstrcat(bstr, \"foo\", 3),\nboth suck a lot, and with an inline function using strlen, most\ncompilers will optimize the strlen away, and the code is way more\nreadable. But again, this is trivial to implement as an extension as\nwell, so I really don't mind that much either.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52324","messageId":"20070903084927.GB21759@artemis.corp","threadId":"9753","inReplyTo":"vpqk5r8m9nz.fsf@bauges.imag.fr","subject":"Re: strbuf API","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-03T08:49:27Z","receivedAt":"2007-09-03T08:49:27Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Mon, Sep 03, 2007 at 08:32:16AM +0000, Matthieu Moy wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> >   First, and that's the most important one: the buffer is always NUL\n> > terminated, after its official \"len\". That means, in terms of strbuf\n> > API, that \"alloc\" is always greater or equal to len+1 to be able to\n> > store the ending NUL[1]. The advantages are obvious: you can pass the\n> > buffer to any legacy C string function without any fear of read\n> > overflow.\n> \n> No overflow, but it's still potentially dangerous: if your strbuf\n> contains a '\\0', you can't use any standard C string function.\n> \n> For example, it would be very tempting to compare files with\n> \"strcmp(buf1, buf2)\", but that would just fail silently when the file\n> contains a '\\0' byte.\n\n  Indeed, OTHO doing that would be pretty silly, as embending NULs in a\nstrbuf is wrong, it's a _str_buf, not a random-binary-buffer. It's meant\nto make the use of strings easier, not to use as generic purpose byte\nbuffers. Of course they can, but well, it's not what they are designed\nfor in the first place.\n\n  Also note that it generates bugs, but never crashes if you still do\nthat, bugs suck, but security bugs, buffer overflows, ... suck more.\n\n  So I'm tempted to say, it's not really a problem.\n\n> >   The other shortcoming is that you cannot tell the buffer \"Hey, it's\n> > very likely that you'll end up being _that_ long.\n>\n> 100% ACK on this point.\n\n  Also note that it seems that bstring lack this, but maybe I'm wrong.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52327","messageId":"vpq8x7om89p.fsf@bauges.imag.fr","threadId":"9753","inReplyTo":"20070903084927.GB21759@artemis.corp","subject":"Re: strbuf API","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2007-09-03T09:02:26Z","receivedAt":"2007-09-03T09:02:26Z","isPatch":false,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   Indeed, OTHO doing that would be pretty silly, as embending NULs in a\n> strbuf is wrong, it's a _str_buf, not a random-binary-buffer.\n\nI see nothing in strbuf that prevents you from embedding '\\0' in it.\nAnd the git code calls read_line on stdin, which may well contain\n'\\0'. So, either I missed something, or strbuf can contain '\\0', or\nthe git code is not robust to null-characters on stdin, and should be\nfixed.\n\n-- \nMatthieu\n"},{"id":"52331","messageId":"7vejhgksza.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"20070903084927.GB21759@artemis.corp","subject":"Re: strbuf API","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-03T09:18:01Z","receivedAt":"2007-09-03T09:18:01Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n> On Mon, Sep 03, 2007 at 08:32:16AM +0000, Matthieu Moy wrote:\n>>  ...\n>> For example, it would be very tempting to compare files with\n>> \"strcmp(buf1, buf2)\", but that would just fail silently when the file\n>> contains a '\\0' byte.\n>\n>   Indeed, OTHO doing that would be pretty silly, as embending NULs in a\n> strbuf is wrong, it's a _str_buf, not a random-binary-buffer. It's meant\n> to make the use of strings easier, not to use as generic purpose byte\n> buffers. Of course they can, but well, it's not what they are designed\n> for in the first place.\n\nPeople, please realize strbuf \"API\" is not a serious API.  \n\nIt wasn't even intended to be anything more than just a\nquick-and-dirty implementation of fgets that can grow\ndynamically.  The other callers added by people to have it do\ngeneral string manipulations were just bolted-on, not designed.\nI haven't taken a serious look at bstring nor any of the\nalternatives yet, but defending strbuf as if it was designed to\nbe a sane API is just silly.\n"},{"id":"52346","messageId":"20070903115328.GC21759@artemis.corp","threadId":"9753","inReplyTo":"7vejhgksza.fsf@gitster.siamese.dyndns.org","subject":"Re: strbuf API","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-03T11:53:28Z","receivedAt":"2007-09-03T11:53:28Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Mon, Sep 03, 2007 at 09:18:01AM +0000, Junio C Hamano wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> > On Mon, Sep 03, 2007 at 08:32:16AM +0000, Matthieu Moy wrote:\n> >>  ...\n> >> For example, it would be very tempting to compare files with\n> >> \"strcmp(buf1, buf2)\", but that would just fail silently when the file\n> >> contains a '\\0' byte.\n> >\n> >   Indeed, OTHO doing that would be pretty silly, as embending NULs in a\n> > strbuf is wrong, it's a _str_buf, not a random-binary-buffer. It's meant\n> > to make the use of strings easier, not to use as generic purpose byte\n> > buffers. Of course they can, but well, it's not what they are designed\n> > for in the first place.\n> \n> People, please realize strbuf \"API\" is not a serious API.  \n> \n> It wasn't even intended to be anything more than just a\n> quick-and-dirty implementation of fgets that can grow\n> dynamically.  The other callers added by people to have it do\n> general string manipulations were just bolted-on, not designed.\n> I haven't taken a serious look at bstring nor any of the\n> alternatives yet, but defending strbuf as if it was designed to\n> be a sane API is just silly.\n\n  actually I was defending the \"enhanced\" strbuf API I was proposing\nbefore, sorry if that was unclear.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52349","messageId":"Pine.LNX.4.64.0709031322260.28586@racer.site","threadId":"9753","inReplyTo":"7vejhgksza.fsf@gitster.siamese.dyndns.org","subject":"Re: strbuf API","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-03T12:29:11Z","receivedAt":"2007-09-03T12:29:11Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 3 Sep 2007, Junio C Hamano wrote:\n\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> > On Mon, Sep 03, 2007 at 08:32:16AM +0000, Matthieu Moy wrote:\n> >>  ...\n> >> For example, it would be very tempting to compare files with\n> >> \"strcmp(buf1, buf2)\", but that would just fail silently when the file\n> >> contains a '\\0' byte.\n> >\n> >   Indeed, OTHO doing that would be pretty silly, as embending NULs in a\n> > strbuf is wrong, it's a _str_buf, not a random-binary-buffer. It's meant\n> > to make the use of strings easier, not to use as generic purpose byte\n> > buffers. Of course they can, but well, it's not what they are designed\n> > for in the first place.\n> \n> People, please realize strbuf \"API\" is not a serious API.  \n> \n> It wasn't even intended to be anything more than just a\n> quick-and-dirty implementation of fgets that can grow\n> dynamically.  The other callers added by people to have it do\n> general string manipulations were just bolted-on, not designed.\n> I haven't taken a serious look at bstring nor any of the\n> alternatives yet, but defending strbuf as if it was designed to\n> be a sane API is just silly.\n\nTwo points:\n\n- it can be turned into an API (pretty easy, really, since it is _really_ \n  small), and\n\n- it is easy to hack on, because it is _not_ a full-blown cover-them-all \n  library.  As such, we can tweak it the way _we_ want.  And if that means \n  that we do not NUL terminate, so be it.  And if that means that we turn \n  it into a rope structure, so be it.\n\nIOW it might be utterly incomplete, but at least it can evolve in a manner \nthat we like.  It does not need to be a *kaboom-here-we-have-a-big-dump*.\n\nI know that we had something like that with LibXDiff.  I was not \nparticularly happy with the process, but it turned out quite well, as \nDavide helped us a lot.\n\nBut the diff situation is completely different from the string situation:\n\n- we did not have _anything_ in the way of diff generation,\n\n- it is pretty well defined what a diff generation library should do, and\n\n- diff generation is not trivial, and it would have taken us quite a long \n  time to write it ourselves.\n\nAll three points are not true with string manipulation.\n\nBut code talks, and as I do not have anything presentable (yet), I'll just \nshut up, until I have.\n\nCiao,\nDscho\n"},{"id":"52381","messageId":"buobqcjrycl.fsf@dhapc248.dev.necel.com","threadId":"9753","inReplyTo":"20070903084610.GA21759@artemis.corp","subject":"Re: strbuf API","fromName":"Miles Bader","fromEmail":"miles.bader@necel.com","sentAt":"2007-09-04T01:52:26Z","receivedAt":"2007-09-04T01:52:26Z","isPatch":false,"sender":{"key":"miles.bader@necel.com","avatar":"https://gravatar.com/avatar/be062d4050eb88e04229cbdb60f803e1bd647923a015996c2439e76f23e336a7?d=mp&s=160"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n>   For the record, I dislike the fact that bstring pullutes the b*\n> namespace, whereas it should use bstr as a prefix everywhere, and some\n> functions (like bstrcpy, that should definitely be named bstrdup) are\n> really named the _wrong_ way\n\nYeah, I got the same impression.  There's an odd \"accumulated\nhaphazardly over time\" feel to much of it.\n\n[One thing I found especially weird is the way the \"core\" interface uses\nlowercase names, but the \"aux\" interfaces all seem to use StUDlyCaPS...]\n\n-Miles\n-- \nIch bin ein Virus. Mach' mit und kopiere mich in Deine .signature.\n"},{"id":"52411","messageId":"11888956803429-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"buobqcjrycl.fsf@dhapc248.dev.necel.com","subject":"strbuf new semantics, let's give it a try","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T08:47:58Z","receivedAt":"2007-09-04T08:47:58Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Allright, here is a proposal for a new strbuf semantics like the one I\nproposed before. Like said, with this proposal, strbuf's always have a\n'\\0' at the end of the buffer, not accounted in its length, so that any\nC str* function can still be used.\n\n  The second patch demonstrate that strbufs makes the code smaller,\nsimpler to read, while keeping the exact same efficiency (as may\nmallocs, memcpys, and fread's in that case).\n\n\n  I've tried to keep the amount of inlines low. Though, I wonder if\nstrbuf_add shouldn't be inlined (so that memcpys could be even more\ninlined/optmized by gcc). And strbuf_addstr is inlined so that the\nstrlen call is optimized when the argument is an immediate string.\nMeaning that calling strbuf_addstr(sb, \"foo\") is not sloppy at all.\n\n  I don't really like the buffer growth scheme right now, I just stick\nwith the one that was used in git before. Though I really belive it's\ninelegant as is, and should be simplified (strbuf_extend).\n\nCheers,\n-- \nÂ·OÂ·  Pierre Habouzit\nÂ·Â·O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52413","messageId":"11888956802504-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"buobqcjrycl.fsf@dhapc248.dev.necel.com","subject":"[PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T08:47:59Z","receivedAt":"2007-09-04T08:47:59Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  A strbuf can be used to store byte arrays, or as an extended string\nlibrary. The `buf' member can be passed to any C legacy string function,\nbecause strbuf operations always ensure there is a terminating \\0 at the end\nof the buffer, not accounted in the `len' field of the structure.\n\n  A strbuf can be used to generate a string/buffer whose final size is not\nreally known, and then \"strbuf_detach\" can be used to get the built buffer,\nand keep the wrapping \"strbuf\" structure usable for further work again.\n\n  Other interesting feature: buffer_ensure(sb, size) ensure that there is\nenough allocated space in `sb' to put `size' new octets of data in the\nbuffer. It helps avoiding reallocating data for nothing when the problem the\nstrbuf helps to solve has a known typical size.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n archive-tar.c |   65 +++++++++++++---------------------------------------\n fast-import.c |   24 +++++++++---------\n mktree.c      |    4 +--\n strbuf.c      |   71 +++++++++++++++++++++++++++++++++++++++++++++-----------\n strbuf.h      |   34 +++++++++++++++++++++++++++\n 5 files changed, 120 insertions(+), 78 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 66fe3e3..ccdd7d5 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -78,19 +78,6 @@ static void write_trailer(void)\n \t}\n }\n \n-static void strbuf_append_string(struct strbuf *sb, const char *s)\n-{\n-\tint slen = strlen(s);\n-\tint total = sb->len + slen;\n-\tif (total + 1 > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total + 1);\n-\t\tsb->alloc = total + 1;\n-\t}\n-\tmemcpy(sb->buf + sb->len, s, slen);\n-\tsb->len = total;\n-\tsb->buf[total] = '\\0';\n-}\n-\n /*\n  * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n  * the size of the whole string (including the %u), the first %s is the\n@@ -100,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n                                      const char *value, unsigned int valuelen)\n {\n-\tchar *p;\n-\tint len, total, tmp;\n+\tint len, tmp;\n \n \t/* \"%u %s=%s\\n\" */\n \tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n \tfor (tmp = len; tmp > 9; tmp /= 10)\n \t\tlen++;\n \n-\ttotal = sb->len + len;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\n-\tp = sb->buf;\n-\tp += sprintf(p, \"%u %s=\", len, keyword);\n-\tmemcpy(p, value, valuelen);\n-\tp += valuelen;\n-\t*p = '\\n';\n-\tsb->len = total;\n+\tstrbuf_ensure(sb, len);\n+\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n+\tstrbuf_add(sb, value, valuelen);\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static unsigned int ustar_header_chksum(const struct ustar_header *header)\n@@ -153,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \tstruct strbuf ext_header;\n \n \tmemset(&header, 0, sizeof(header));\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\tstrbuf_init(&ext_header);\n \n \tif (!sha1) {\n \t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n@@ -225,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \n \tif (ext_header.len > 0) {\n \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n-\t\tfree(ext_header.buf);\n \t}\n+\tstrbuf_wipe(&ext_header);\n \twrite_blocked(&header, sizeof(header));\n \tif (S_ISREG(mode) && buffer && size > 0)\n \t\twrite_blocked(buffer, size);\n@@ -235,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n static void write_global_extended_header(const unsigned char *sha1)\n {\n \tstruct strbuf ext_header;\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\n+\tstrbuf_init(&ext_header);\n \tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n \twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n-\tfree(ext_header.buf);\n+\tstrbuf_wipe(&ext_header);\n }\n \n static int git_tar_config(const char *var, const char *value)\n@@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n                            const char *base, int baselen,\n                            const char *filename, unsigned mode, int stage)\n {\n-\tstatic struct strbuf path;\n+\tstatic struct strbuf path = STRBUF_INIT;\n \tint filenamelen = strlen(filename);\n \tvoid *buffer;\n \tenum object_type type;\n \tunsigned long size;\n \n-\tif (!path.alloc) {\n-\t\tpath.buf = xmalloc(PATH_MAX);\n-\t\tpath.alloc = PATH_MAX;\n-\t\tpath.len = path.eof = 0;\n-\t}\n-\tif (path.alloc < baselen + filenamelen + 1) {\n-\t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n-\t\tpath.alloc = baselen + filenamelen + 1;\n-\t}\n-\tmemcpy(path.buf, base, baselen);\n-\tmemcpy(path.buf + baselen, filename, filenamelen);\n-\tpath.len = baselen + filenamelen;\n-\tpath.buf[path.len] = '\\0';\n+\tstrbuf_ensure(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n+\tstrbuf_reset(&path);\n+\tstrbuf_add(&path, base, baselen);\n+\tstrbuf_add(&path, filename, filenamelen);\n \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n-\t\tstrbuf_append_string(&path, \"/\");\n+\t\tstrbuf_addch(&path, '/');\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\ndiff --git a/fast-import.c b/fast-import.c\nindex 078079d..ab3927b 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -340,7 +340,7 @@ static struct tag *last_tag;\n \n /* Input stream parsing */\n static whenspec_type whenspec = WHENSPEC_RAW;\n-static struct strbuf command_buf;\n+static struct strbuf command_buf = STRBUF_INIT;\n static int unread_command_buf;\n static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};\n static struct recent_command *cmd_tail = &cmd_hist;\n@@ -1595,7 +1595,7 @@ static void read_next_command(void)\n \t\t} else {\n \t\t\tstruct recent_command *rc;\n \n-\t\t\tcommand_buf.buf = NULL;\n+\t\t\tstrbuf_detach(&command_buf);\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n \t\t\t\treturn;\n@@ -1610,7 +1610,7 @@ static void read_next_command(void)\n \t\t\t\tfree(rc->buf);\n \t\t\t}\n \n-\t\t\trc->buf = command_buf.buf;\n+\t\t\trc->buf  = command_buf.buf;\n \t\t\trc->prev = cmd_tail;\n \t\t\trc->next = cmd_hist.prev;\n \t\t\trc->prev->next = rc;\n@@ -1649,7 +1649,9 @@ static void *cmd_data (size_t *size)\n \t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n \t\tlength = 0;\n \t\tbuffer = xmalloc(sz);\n-\t\tcommand_buf.buf = NULL;\n+\n+\t\t/* XXX possible memory leak ? */\n+\t\tstrbuf_detach(&command_buf);\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1657,11 +1659,9 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len, sz);\n-\t\t\tmemcpy(buffer + length,\n-\t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len - 1);\n-\t\t\tlength += command_buf.len - 1;\n+\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n+\t\t\tmemcpy(buffer + length, command_buf.buf, command_buf.len);\n+\t\t\tlength += command_buf.len;\n \t\t\tbuffer[length++] = '\\n';\n \t\t}\n \t\tfree(term);\n@@ -2101,7 +2101,7 @@ static void cmd_new_commit(void)\n \t}\n \n \t/* file_change* */\n-\twhile (!command_buf.eof && command_buf.len > 1) {\n+\twhile (!command_buf.eof && command_buf.len > 0) {\n \t\tif (!prefixcmp(command_buf.buf, \"M \"))\n \t\t\tfile_change_m(b);\n \t\telse if (!prefixcmp(command_buf.buf, \"D \"))\n@@ -2256,7 +2256,7 @@ static void cmd_reset_branch(void)\n \telse\n \t\tb = new_branch(sp);\n \tread_next_command();\n-\tif (!cmd_from(b) && command_buf.len > 1)\n+\tif (!cmd_from(b) && command_buf.len > 0)\n \t\tunread_command_buf = 1;\n }\n \n@@ -2273,7 +2273,7 @@ static void cmd_checkpoint(void)\n \n static void cmd_progress(void)\n {\n-\tfwrite(command_buf.buf, 1, command_buf.len - 1, stdout);\n+\tfwrite(command_buf.buf, 1, command_buf.len, stdout);\n \tfputc('\\n', stdout);\n \tfflush(stdout);\n \tskip_optional_lf();\ndiff --git a/mktree.c b/mktree.c\nindex d86dde8..86de5eb 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -92,7 +92,6 @@ int main(int ac, char **av)\n \n \tstrbuf_init(&sb);\n \twhile (1) {\n-\t\tint len;\n \t\tchar *ptr, *ntr;\n \t\tunsigned mode;\n \t\tenum object_type type;\n@@ -101,7 +100,6 @@ int main(int ac, char **av)\n \t\tread_line(&sb, stdin, line_termination);\n \t\tif (sb.eof)\n \t\t\tbreak;\n-\t\tlen = sb.len;\n \t\tptr = sb.buf;\n \t\t/* Input is non-recursive ls-tree output format\n \t\t * mode SP type SP sha1 TAB name\n@@ -111,7 +109,7 @@ int main(int ac, char **av)\n \t\t\tdie(\"input format error: %s\", sb.buf);\n \t\tptr = ntr + 1; /* type */\n \t\tntr = strchr(ptr, ' ');\n-\t\tif (!ntr || sb.buf + len <= ntr + 41 ||\n+\t\tif (!ntr || sb.buf + sb.len <= ntr + 40 ||\n \t\t    ntr[41] != '\\t' ||\n \t\t    get_sha1_hex(ntr + 1, sha1))\n \t\t\tdie(\"input format error: %s\", sb.buf);\ndiff --git a/strbuf.c b/strbuf.c\nindex e33d06b..86d5965 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -2,40 +2,83 @@\n #include \"strbuf.h\"\n \n void strbuf_init(struct strbuf *sb) {\n-\tsb->buf = NULL;\n-\tsb->eof = sb->alloc = sb->len = 0;\n+\tmemset(sb, 0, sizeof(*sb));\n }\n \n-static void strbuf_begin(struct strbuf *sb) {\n+void strbuf_wipe(struct strbuf *sb) {\n \tfree(sb->buf);\n-\tstrbuf_init(sb);\n+\tmemset(sb, 0, sizeof(*sb));\n }\n \n-static void inline strbuf_add(struct strbuf *sb, int ch) {\n-\tif (sb->alloc <= sb->len) {\n-\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n+void strbuf_reset(struct strbuf *sb) {\n+\tif (sb->len)\n+\t\tsb->buf[sb->len = 0] = '\\0';\n+}\n+\n+char *strbuf_detach(struct strbuf *sb) {\n+    char *res = sb->buf;\n+    strbuf_init(sb);\n+    return res;\n+}\n+\n+void strbuf_ensure(struct strbuf *sb, int extra) {\n+\tif (sb->len + extra >= sb->alloc) {\n+\t\twhile (sb->len + extra >= sb->alloc)\n+\t\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n \t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n \t}\n-\tsb->buf[sb->len++] = ch;\n }\n \n-static void strbuf_end(struct strbuf *sb) {\n-\tstrbuf_add(sb, 0);\n+void strbuf_add(struct strbuf *sb, const void *data, int len) {\n+\tstrbuf_ensure(sb, len);\n+\tmemcpy(sb->buf + sb->len, data, len);\n+\tsb->len += len;\n+\tsb->buf[sb->len] = '\\0';\n+}\n+\n+void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)\n+{\n+\tint len;\n+\tva_list ap2;\n+\n+\tva_copy(ap2, ap);\n+\n+\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n+\tif (len < 0) {\n+\t\tlen = 0;\n+\t}\n+\tif (len >= sb->alloc - sb->len) {\n+\t\tstrbuf_ensure(sb, len);\n+\t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap2);\n+\t\tif (len >= sb->alloc - sb->len) {\n+\t\t\tlen = sb->alloc - sb->len - 1;\n+\t\t}\n+\t}\n+\tsb->len = sb->len + len;\n+\tsb->buf[sb->len] = '\\0';\n }\n \n void read_line(struct strbuf *sb, FILE *fp, int term) {\n \tint ch;\n-\tstrbuf_begin(sb);\n \tif (feof(fp)) {\n+\t\tstrbuf_wipe(sb);\n \t\tsb->eof = 1;\n \t\treturn;\n \t}\n+\n+\tstrbuf_reset(sb);\n \twhile ((ch = fgetc(fp)) != EOF) {\n \t\tif (ch == term)\n \t\t\tbreak;\n-\t\tstrbuf_add(sb, ch);\n+\t\tstrbuf_ensure(sb, 1);\n+\t\tsb->buf[sb->len++] = ch;\n \t}\n-\tif (ch == EOF && sb->len == 0)\n+\tif (ch == EOF && sb->len == 0) {\n+\t\tstrbuf_wipe(sb);\n \t\tsb->eof = 1;\n-\tstrbuf_end(sb);\n+\t}\n+\n+\tstrbuf_ensure(sb, 1);\n+\tsb->buf[sb->len] = '\\0';\n }\n+\ndiff --git a/strbuf.h b/strbuf.h\nindex 74cc012..ee72419 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -7,7 +7,41 @@ struct strbuf {\n \tchar *buf;\n };\n \n+#define STRBUF_INIT  { 0, 0, 0, NULL }\n+\n+/* strbuf life cycle */\n extern void strbuf_init(struct strbuf *);\n+extern void strbuf_wipe(struct strbuf *);\n+extern void strbuf_reset(struct strbuf *);\n+extern char *strbuf_detach(struct strbuf *);\n+\n+\n+extern void strbuf_ensure(struct strbuf *, int);\n+extern void strbuf_add(struct strbuf *, const void *data, int len);\n+\n+static inline void strbuf_addstr(struct strbuf *sb, const char *s) {\n+\tstrbuf_add(sb, s, strlen(s));\n+}\n+static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {\n+\tstrbuf_add(sb, sb2->buf, sb2->len);\n+}\n+static inline void strbuf_addch(struct strbuf *sb, int c) {\n+\tstrbuf_ensure(sb, 1);\n+\tsb->buf[sb->len++] = c;\n+\tsb->buf[sb->len] = '\\0';\n+}\n+\n+__attribute__((format(printf,2,0)))\n+extern void strbuf_addvf(struct strbuf *, const char *, va_list);\n+\n+static inline __attribute__((format(printf,2,3)))\n+void strbuf_addf(struct strbuf *sb, const char *fmt, ...) {\n+\tva_list ap;\n+\tva_start(ap, fmt);\n+\tstrbuf_addvf(sb, fmt, ap);\n+\tva_end(ap);\n+}\n+\n extern void read_line(struct strbuf *, FILE *, int);\n \n #endif /* STRBUF_H */\n-- \n1.5.3\n"},{"id":"52412","messageId":"11888956801971-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"buobqcjrycl.fsf@dhapc248.dev.necel.com","subject":"[PATCH] Add strbuf_fread, use it in fast-import.c.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T08:48:00Z","receivedAt":"2007-09-04T08:48:00Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This is a good proof of concept that combined with strbuf_detach it often\nhelps improving readability a lot, while remaining as efficient as before.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n fast-import.c |   26 ++++++++++----------------\n strbuf.c      |   12 ++++++++++++\n strbuf.h      |    3 +++\n 3 files changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex ab3927b..2d8daeb 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1638,20 +1638,15 @@ static void cmd_mark(void)\n \n static void *cmd_data (size_t *size)\n {\n-\tsize_t length;\n-\tchar *buffer;\n+\tstruct strbuf buffer = STRBUF_INIT;\n \n \tif (prefixcmp(command_buf.buf, \"data \"))\n \t\tdie(\"Expected 'data n' command, found: %s\", command_buf.buf);\n \n \tif (!prefixcmp(command_buf.buf + 5, \"<<\")) {\n \t\tchar *term = xstrdup(command_buf.buf + 5 + 2);\n-\t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n-\t\tlength = 0;\n-\t\tbuffer = xmalloc(sz);\n+\t\tsize_t term_len = command_buf.len - 5 - 2;\n \n-\t\t/* XXX possible memory leak ? */\n-\t\tstrbuf_detach(&command_buf);\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1659,19 +1654,18 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n-\t\t\tmemcpy(buffer + length, command_buf.buf, command_buf.len);\n-\t\t\tlength += command_buf.len;\n-\t\t\tbuffer[length++] = '\\n';\n+\t\t\tstrbuf_addbuf(&buffer, &command_buf);\n+\t\t\tstrbuf_addch(&buffer, '\\n');\n \t\t}\n \t\tfree(term);\n \t}\n \telse {\n-\t\tsize_t n = 0;\n+\t\tsize_t n = 0, length;\n+\n \t\tlength = strtoul(command_buf.buf + 5, NULL, 10);\n-\t\tbuffer = xmalloc(length);\n+\n \t\twhile (n < length) {\n-\t\t\tsize_t s = fread(buffer + n, 1, length - n, stdin);\n+\t\t\tsize_t s = strbuf_fread(&buffer, length - n, stdin);\n \t\t\tif (!s && feof(stdin))\n \t\t\t\tdie(\"EOF in data (%lu bytes remaining)\",\n \t\t\t\t\t(unsigned long)(length - n));\n@@ -1680,8 +1674,8 @@ static void *cmd_data (size_t *size)\n \t}\n \n \tskip_optional_lf();\n-\t*size = length;\n-\treturn buffer;\n+\t*size = buffer.len;\n+\treturn strbuf_detach(&buffer);\n }\n \n static int validate_raw_date(const char *src, char *result, int maxlen)\ndiff --git a/strbuf.c b/strbuf.c\nindex 86d5965..693fbcf 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -58,6 +58,18 @@ void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)\n \tsb->buf[sb->len] = '\\0';\n }\n \n+size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) {\n+\tsize_t res;\n+\n+\tstrbuf_ensure(sb, size);\n+\tres = fread(sb->buf + sb->len, 1, size, f);\n+\tif (res > 0) {\n+\t\tsb->len += res;\n+\t\tsb->buf[sb->len] = '\\0';\n+\t}\n+\treturn res;\n+}\n+\n void read_line(struct strbuf *sb, FILE *fp, int term) {\n \tint ch;\n \tif (feof(fp)) {\ndiff --git a/strbuf.h b/strbuf.h\nindex ee72419..20c5255 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -42,6 +42,9 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) {\n \tva_end(ap);\n }\n \n+\n+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n+\n extern void read_line(struct strbuf *, FILE *, int);\n \n #endif /* STRBUF_H */\n-- \n1.5.3\n"},{"id":"52422","messageId":"Pine.LNX.4.64.0709041209280.28586@racer.site","threadId":"9753","inReplyTo":"11888956802504-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-04T11:11:45Z","receivedAt":"2007-09-04T11:11:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 4 Sep 2007, Pierre Habouzit wrote:\n\n>   A strbuf can be used to store byte arrays, or as an extended string \n> library. The `buf' member can be passed to any C legacy string function, \n> because strbuf operations always ensure there is a terminating \\0 at the \n> end of the buffer, not accounted in the `len' field of the structure.\n> \n>   A strbuf can be used to generate a string/buffer whose final size is \n> not really known, and then \"strbuf_detach\" can be used to get the built \n> buffer, and keep the wrapping \"strbuf\" structure usable for further work \n> again.\n> \n>   Other interesting feature: buffer_ensure(sb, size) ensure that there \n> is enough allocated space in `sb' to put `size' new octets of data in \n> the buffer. It helps avoiding reallocating data for nothing when the \n> problem the strbuf helps to solve has a known typical size.\n\nI like the general idea of this!\n\nHowever, some comments are due:\n\n- IMHO strbuf_grow() would be more descriptive than buffer_ensure(),\n\n- IMHO the same goes for strbuf_free() instead of strbuf_wipe(), and\n\n- it would be nice to split this patch into\n\n\t- the API change (with _minimal_ changes to anything outside of \n\t  strbuf.[ch]), and\n\n\t- the cleanups in the rest of the code.\n\nCiao,\nDscho\n"},{"id":"52426","messageId":"20070904115317.GA3381@artemis.corp","threadId":"9753","inReplyTo":"Pine.LNX.4.64.0709041209280.28586@racer.site","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T11:53:17Z","receivedAt":"2007-09-04T11:53:17Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Tue, Sep 04, 2007 at 11:11:45AM +0000, Johannes Schindelin wrote:\n> Hi,\n> \n> On Tue, 4 Sep 2007, Pierre Habouzit wrote:\n> \n> >   A strbuf can be used to store byte arrays, or as an extended string \n> > library. The `buf' member can be passed to any C legacy string function, \n> > because strbuf operations always ensure there is a terminating \\0 at the \n> > end of the buffer, not accounted in the `len' field of the structure.\n> > \n> >   A strbuf can be used to generate a string/buffer whose final size is \n> > not really known, and then \"strbuf_detach\" can be used to get the built \n> > buffer, and keep the wrapping \"strbuf\" structure usable for further work \n> > again.\n> > \n> >   Other interesting feature: buffer_ensure(sb, size) ensure that there \n> > is enough allocated space in `sb' to put `size' new octets of data in \n> > the buffer. It helps avoiding reallocating data for nothing when the \n> > problem the strbuf helps to solve has a known typical size.\n> \n> I like the general idea of this!\n> \n> However, some comments are due:\n> \n> - IMHO strbuf_grow() would be more descriptive than buffer_ensure(),\n\n  Yeah, strbuf_ensure (and not buffer_ensure sorry :P) isn't a clever\nname. strbuf_grow looks better indeed.\n\n> - IMHO the same goes for strbuf_free() instead of strbuf_wipe(), and\n\n  Well, I don't like strbuf_free, because it's opposed to\nstrbuf_alloc/new whatever, that would be functions that create and\nrelease a struct strbuf * (meaning allocating the struct shell as well).\nHere you only free the internal buffer, not the shell, so _free() would\nbe a very bad name.\n\n  In my own coding rules, I have _new/_delete and _init/_wipe functions,\nthe former acts on pointers, the latter on the structs. Hence the\nnaming. Though, looking at git's code, it seems that the usual name for\nthis operation is _release. So would you go for strbuf_release ?\n\n\n> - it would be nice to split this patch into\n> \n> \t- the API change (with _minimal_ changes to anything outside of \n> \t  strbuf.[ch]), and\n> \n> \t- the cleanups in the rest of the code.\n\n  I'll try to do that, but it's quite hard to achieve knowing that in\nmany places of the current state of master, there are embeded NUL's\n(accounted in ->len). I'll try to see what I can split, but it's\nunlikely I'll be able to have an intermediate _working_ state (I mean\nthat would pass the testsuite) with the new API/semantics _and_ without\ntouching a lot less of the rest of the code.\n\n  But I really understand that it helps seeing what the new API\nimproves, whereas right now it may not be that obvious because of the\n(not so) many new lines in strbuf.[hc].\n\n\n  I'll try to roll a new patchset ASAP.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52436","messageId":"46DD5EF4.3090309@op5.se","threadId":"9753","inReplyTo":"20070904115317.GA3381@artemis.corp","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-09-04T13:34:44Z","receivedAt":"2007-09-04T13:34:44Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Pierre Habouzit wrote:\n> On Tue, Sep 04, 2007 at 11:11:45AM +0000, Johannes Schindelin wrote:\n>> Hi,\n>>\n>> On Tue, 4 Sep 2007, Pierre Habouzit wrote:\n>>\n>> - IMHO the same goes for strbuf_free() instead of strbuf_wipe(), and\n> \n>   Well, I don't like strbuf_free, because it's opposed to\n> strbuf_alloc/new whatever, that would be functions that create and\n> release a struct strbuf * (meaning allocating the struct shell as well).\n> Here you only free the internal buffer, not the shell, so _free() would\n> be a very bad name.\n> \n>   In my own coding rules, I have _new/_delete and _init/_wipe functions,\n> the former acts on pointers, the latter on the structs. Hence the\n> naming. Though, looking at git's code, it seems that the usual name for\n> this operation is _release. So would you go for strbuf_release ?\n> \n\nrelease is indeed better. To me, \"wipe\" means zeroing out (possibly after\nan optional number of passes writing trash to the memory area) rather than\nactually freeing any memory.\n\n> \n>> - it would be nice to split this patch into\n>>\n>> \t- the API change (with _minimal_ changes to anything outside of \n>> \t  strbuf.[ch]), and\n>>\n>> \t- the cleanups in the rest of the code.\n> \n>   I'll try to do that, but it's quite hard to achieve knowing that in\n> many places of the current state of master, there are embeded NUL's\n> (accounted in ->len). I'll try to see what I can split, but it's\n> unlikely I'll be able to have an intermediate _working_ state (I mean\n> that would pass the testsuite) with the new API/semantics _and_ without\n> touching a lot less of the rest of the code.\n> \n\nAlways having a compilable/operational tree is pretty nice primarily due\nto bisect. If the code turns from working to non-working in between,\nmake sure to jot it down in the commit message.\n\nIt might even be better to add the embedded NUL handling code in the\nfirst patch, modify the callers in the second, and remove the embedded\nNUL handling in a third.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"52444","messageId":"11889144741644-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"20070904115317.GA3381@artemis.corp","subject":"[PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T14:01:12Z","receivedAt":"2007-09-04T14:01:12Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  A strbuf can be used to store byte arrays, or as an extended string\nlibrary. The `buf' member can be passed to any C legacy string function,\nbecause strbuf operations always ensure there is a terminating \\0 at the end\nof the buffer, not accounted in the `len' field of the structure.\n\n  A strbuf can be used to generate a string/buffer whose final size is not\nreally known, and then \"strbuf_detach\" can be used to get the built buffer,\nand keep the wrapping \"strbuf\" structure usable for further work again.\n\n  Other interesting feature: strbuf_grow(sb, size) ensure that there is\nenough allocated space in `sb' to put `size' new octets of data in the\nbuffer. It helps avoiding reallocating data for nothing when the problem the\nstrbuf helps to solve has a known typical size.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n archive-tar.c |    2 +-\n fast-import.c |   15 +++++-----\n mktree.c      |    4 +--\n strbuf.c      |   85 +++++++++++++++++++++++++++++++++++++++++++++++---------\n strbuf.h      |   41 ++++++++++++++++++++++++++-\n 5 files changed, 119 insertions(+), 28 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 66fe3e3..a0763c5 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -166,7 +166,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \t\tsprintf(header.name, \"%s.paxheader\", sha1_to_hex(sha1));\n \t} else {\n \t\tif (verbose)\n-\t\t\tfprintf(stderr, \"%.*s\\n\", path->len, path->buf);\n+\t\t\tfprintf(stderr, \"%.*s\\n\", (int)path->len, path->buf);\n \t\tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n \t\t\t*header.typeflag = TYPEFLAG_DIR;\n \t\t\tmode = (mode | 0777) & ~tar_umask;\ndiff --git a/fast-import.c b/fast-import.c\nindex 078079d..2f7baf4 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1595,7 +1595,7 @@ static void read_next_command(void)\n \t\t} else {\n \t\t\tstruct recent_command *rc;\n \n-\t\t\tcommand_buf.buf = NULL;\n+\t\t\tstrbuf_detach(&command_buf);\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n \t\t\t\treturn;\n@@ -1649,7 +1649,6 @@ static void *cmd_data (size_t *size)\n \t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n \t\tlength = 0;\n \t\tbuffer = xmalloc(sz);\n-\t\tcommand_buf.buf = NULL;\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1657,11 +1656,11 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len, sz);\n+\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n \t\t\tmemcpy(buffer + length,\n \t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len - 1);\n-\t\t\tlength += command_buf.len - 1;\n+\t\t\t\tcommand_buf.len);\n+\t\t\tlength += command_buf.len;\n \t\t\tbuffer[length++] = '\\n';\n \t\t}\n \t\tfree(term);\n@@ -2101,7 +2100,7 @@ static void cmd_new_commit(void)\n \t}\n \n \t/* file_change* */\n-\twhile (!command_buf.eof && command_buf.len > 1) {\n+\twhile (!command_buf.eof && command_buf.len > 0) {\n \t\tif (!prefixcmp(command_buf.buf, \"M \"))\n \t\t\tfile_change_m(b);\n \t\telse if (!prefixcmp(command_buf.buf, \"D \"))\n@@ -2256,7 +2255,7 @@ static void cmd_reset_branch(void)\n \telse\n \t\tb = new_branch(sp);\n \tread_next_command();\n-\tif (!cmd_from(b) && command_buf.len > 1)\n+\tif (!cmd_from(b) && command_buf.len > 0)\n \t\tunread_command_buf = 1;\n }\n \n@@ -2273,7 +2272,7 @@ static void cmd_checkpoint(void)\n \n static void cmd_progress(void)\n {\n-\tfwrite(command_buf.buf, 1, command_buf.len - 1, stdout);\n+\tfwrite(command_buf.buf, 1, command_buf.len, stdout);\n \tfputc('\\n', stdout);\n \tfflush(stdout);\n \tskip_optional_lf();\ndiff --git a/mktree.c b/mktree.c\nindex d86dde8..86de5eb 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -92,7 +92,6 @@ int main(int ac, char **av)\n \n \tstrbuf_init(&sb);\n \twhile (1) {\n-\t\tint len;\n \t\tchar *ptr, *ntr;\n \t\tunsigned mode;\n \t\tenum object_type type;\n@@ -101,7 +100,6 @@ int main(int ac, char **av)\n \t\tread_line(&sb, stdin, line_termination);\n \t\tif (sb.eof)\n \t\t\tbreak;\n-\t\tlen = sb.len;\n \t\tptr = sb.buf;\n \t\t/* Input is non-recursive ls-tree output format\n \t\t * mode SP type SP sha1 TAB name\n@@ -111,7 +109,7 @@ int main(int ac, char **av)\n \t\t\tdie(\"input format error: %s\", sb.buf);\n \t\tptr = ntr + 1; /* type */\n \t\tntr = strchr(ptr, ' ');\n-\t\tif (!ntr || sb.buf + len <= ntr + 41 ||\n+\t\tif (!ntr || sb.buf + sb.len <= ntr + 40 ||\n \t\t    ntr[41] != '\\t' ||\n \t\t    get_sha1_hex(ntr + 1, sha1))\n \t\t\tdie(\"input format error: %s\", sb.buf);\ndiff --git a/strbuf.c b/strbuf.c\nindex e33d06b..db19007 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,41 +1,98 @@\n #include \"cache.h\"\n #include \"strbuf.h\"\n \n+#define STRBUF_GROW_STEP  (1 << 10)  /* must be a power of 2 */\n+\n void strbuf_init(struct strbuf *sb) {\n-\tsb->buf = NULL;\n-\tsb->eof = sb->alloc = sb->len = 0;\n+\tmemset(sb, 0, sizeof(*sb));\n }\n \n-static void strbuf_begin(struct strbuf *sb) {\n+void strbuf_release(struct strbuf *sb) {\n \tfree(sb->buf);\n+\tmemset(sb, 0, sizeof(*sb));\n+}\n+\n+void strbuf_reset(struct strbuf *sb) {\n+\tif (sb->len)\n+\t\tsb->buf[sb->len = 0] = '\\0';\n+}\n+\n+char *strbuf_detach(struct strbuf *sb) {\n+\tchar *res = sb->buf;\n \tstrbuf_init(sb);\n+\treturn res;\n+}\n+\n+void strbuf_grow(struct strbuf *sb, size_t extra) {\n+\tif (sb->len + extra + STRBUF_GROW_STEP < sb->len)\n+\t\tdie(\"you want to use way to much memory\");\n+\n+\tsb->alloc = ((sb->len + extra) + STRBUF_GROW_STEP) & ~(STRBUF_GROW_STEP - 1);\n+\tsb->buf   = xrealloc(sb->buf, sb->alloc);\n+}\n+\n+void strbuf_add(struct strbuf *sb, const void *data, size_t len) {\n+\tstrbuf_grow(sb, len);\n+\tmemcpy(sb->buf + sb->len, data, len);\n+\tsb->len += len;\n+\tsb->buf[sb->len] = '\\0';\n }\n \n-static void inline strbuf_add(struct strbuf *sb, int ch) {\n-\tif (sb->alloc <= sb->len) {\n-\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n-\t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n+void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)\n+{\n+\tsize_t len;\n+\tva_list ap2;\n+\n+\tva_copy(ap2, ap);\n+\n+\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n+\tif (len < 0) {\n+\t\tlen = 0;\n+\t}\n+\tif (len >= sb->alloc - sb->len) {\n+\t\tstrbuf_grow(sb, len);\n+\t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap2);\n+\t\tif (len >= sb->alloc - sb->len) {\n+\t\t\tlen = sb->alloc - sb->len - 1;\n+\t\t}\n \t}\n-\tsb->buf[sb->len++] = ch;\n+\tsb->len = sb->len + len;\n+\tsb->buf[sb->len] = '\\0';\n }\n \n-static void strbuf_end(struct strbuf *sb) {\n-\tstrbuf_add(sb, 0);\n+size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) {\n+\tsize_t res;\n+\n+\tstrbuf_grow(sb, size);\n+\tres = fread(sb->buf + sb->len, 1, size, f);\n+\tif (res > 0) {\n+\t\tsb->len += res;\n+\t\tsb->buf[sb->len] = '\\0';\n+\t}\n+\treturn res;\n }\n \n void read_line(struct strbuf *sb, FILE *fp, int term) {\n \tint ch;\n-\tstrbuf_begin(sb);\n \tif (feof(fp)) {\n+\t\tstrbuf_release(sb);\n \t\tsb->eof = 1;\n \t\treturn;\n \t}\n+\n+\tstrbuf_reset(sb);\n \twhile ((ch = fgetc(fp)) != EOF) {\n \t\tif (ch == term)\n \t\t\tbreak;\n-\t\tstrbuf_add(sb, ch);\n+\t\tstrbuf_grow(sb, 1);\n+\t\tsb->buf[sb->len++] = ch;\n \t}\n-\tif (ch == EOF && sb->len == 0)\n+\tif (ch == EOF && sb->len == 0) {\n+\t\tstrbuf_release(sb);\n \t\tsb->eof = 1;\n-\tstrbuf_end(sb);\n+\t}\n+\n+\tstrbuf_grow(sb, 1);\n+\tsb->buf[sb->len] = '\\0';\n }\n+\ndiff --git a/strbuf.h b/strbuf.h\nindex 74cc012..ec50eeb 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -1,13 +1,50 @@\n #ifndef STRBUF_H\n #define STRBUF_H\n struct strbuf {\n-\tint alloc;\n-\tint len;\n+\tsize_t alloc;\n+\tsize_t len;\n \tint eof;\n \tchar *buf;\n };\n \n+#define STRBUF_INIT  { 0, 0, 0, NULL }\n+\n+/* strbuf life cycle */\n extern void strbuf_init(struct strbuf *);\n+extern void strbuf_release(struct strbuf *);\n+extern void strbuf_reset(struct strbuf *);\n+extern char *strbuf_detach(struct strbuf *);\n+\n+\n+extern void strbuf_grow(struct strbuf *, size_t);\n+extern void strbuf_add(struct strbuf *, const void *, size_t);\n+\n+static inline void strbuf_addstr(struct strbuf *sb, const char *s) {\n+\tstrbuf_add(sb, s, strlen(s));\n+}\n+static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {\n+\tstrbuf_add(sb, sb2->buf, sb2->len);\n+}\n+static inline void strbuf_addch(struct strbuf *sb, size_t c) {\n+\tstrbuf_grow(sb, 1);\n+\tsb->buf[sb->len++] = c;\n+\tsb->buf[sb->len] = '\\0';\n+}\n+\n+__attribute__((format(printf,2,0)))\n+extern void strbuf_addvf(struct strbuf *, const char *, va_list);\n+\n+static inline __attribute__((format(printf,2,3)))\n+void strbuf_addf(struct strbuf *sb, const char *fmt, ...) {\n+\tva_list ap;\n+\tva_start(ap, fmt);\n+\tstrbuf_addvf(sb, fmt, ap);\n+\tva_end(ap);\n+}\n+\n+\n+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n+\n extern void read_line(struct strbuf *, FILE *, int);\n \n #endif /* STRBUF_H */\n-- \n1.5.3\n"},{"id":"52442","messageId":"11889144743483-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"20070904115317.GA3381@artemis.corp","subject":"[PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T14:01:13Z","receivedAt":"2007-09-04T14:01:13Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This is just cleaner way to deal with strbufs, using its API rather than\nreinventing it in the module (e.g. strbuf_append_string is just the plain\nstrbuf_addstr function, and it was used to perform what strbuf_addch does\nanyways).\n---\n archive-tar.c |   65 ++++++++++++++-------------------------------------------\n 1 files changed, 16 insertions(+), 49 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex a0763c5..c84d7c0 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -78,19 +78,6 @@ static void write_trailer(void)\n \t}\n }\n \n-static void strbuf_append_string(struct strbuf *sb, const char *s)\n-{\n-\tint slen = strlen(s);\n-\tint total = sb->len + slen;\n-\tif (total + 1 > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total + 1);\n-\t\tsb->alloc = total + 1;\n-\t}\n-\tmemcpy(sb->buf + sb->len, s, slen);\n-\tsb->len = total;\n-\tsb->buf[total] = '\\0';\n-}\n-\n /*\n  * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n  * the size of the whole string (including the %u), the first %s is the\n@@ -100,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n                                      const char *value, unsigned int valuelen)\n {\n-\tchar *p;\n-\tint len, total, tmp;\n+\tint len, tmp;\n \n \t/* \"%u %s=%s\\n\" */\n \tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n \tfor (tmp = len; tmp > 9; tmp /= 10)\n \t\tlen++;\n \n-\ttotal = sb->len + len;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\n-\tp = sb->buf;\n-\tp += sprintf(p, \"%u %s=\", len, keyword);\n-\tmemcpy(p, value, valuelen);\n-\tp += valuelen;\n-\t*p = '\\n';\n-\tsb->len = total;\n+\tstrbuf_grow(sb, len);\n+\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n+\tstrbuf_add(sb, value, valuelen);\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static unsigned int ustar_header_chksum(const struct ustar_header *header)\n@@ -153,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \tstruct strbuf ext_header;\n \n \tmemset(&header, 0, sizeof(header));\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\tstrbuf_init(&ext_header);\n \n \tif (!sha1) {\n \t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n@@ -225,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \n \tif (ext_header.len > 0) {\n \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n-\t\tfree(ext_header.buf);\n \t}\n+\tstrbuf_release(&ext_header);\n \twrite_blocked(&header, sizeof(header));\n \tif (S_ISREG(mode) && buffer && size > 0)\n \t\twrite_blocked(buffer, size);\n@@ -235,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n static void write_global_extended_header(const unsigned char *sha1)\n {\n \tstruct strbuf ext_header;\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\n+\tstrbuf_init(&ext_header);\n \tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n \twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n-\tfree(ext_header.buf);\n+\tstrbuf_release(&ext_header);\n }\n \n static int git_tar_config(const char *var, const char *value)\n@@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n                            const char *base, int baselen,\n                            const char *filename, unsigned mode, int stage)\n {\n-\tstatic struct strbuf path;\n+\tstatic struct strbuf path = STRBUF_INIT;\n \tint filenamelen = strlen(filename);\n \tvoid *buffer;\n \tenum object_type type;\n \tunsigned long size;\n \n-\tif (!path.alloc) {\n-\t\tpath.buf = xmalloc(PATH_MAX);\n-\t\tpath.alloc = PATH_MAX;\n-\t\tpath.len = path.eof = 0;\n-\t}\n-\tif (path.alloc < baselen + filenamelen + 1) {\n-\t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n-\t\tpath.alloc = baselen + filenamelen + 1;\n-\t}\n-\tmemcpy(path.buf, base, baselen);\n-\tmemcpy(path.buf + baselen, filename, filenamelen);\n-\tpath.len = baselen + filenamelen;\n-\tpath.buf[path.len] = '\\0';\n+\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n+\tstrbuf_reset(&path);\n+\tstrbuf_add(&path, base, baselen);\n+\tstrbuf_add(&path, filename, filenamelen);\n \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n-\t\tstrbuf_append_string(&path, \"/\");\n+\t\tstrbuf_addch(&path, '/');\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\n-- \n1.5.3\n"},{"id":"52443","messageId":"11889144741561-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"20070904115317.GA3381@artemis.corp","subject":"[PATCH] Use proper strbuf API, and also simplify cmd_data code.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T14:01:14Z","receivedAt":"2007-09-04T14:01:14Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This patch features the use of strbuf_detach, and prevent the programmer\nto mess with allocation directly. The code is as efficent as before, just\nmore concise and more straightforward.\n---\n fast-import.c |   29 ++++++++++++-----------------\n 1 files changed, 12 insertions(+), 17 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2f7baf4..1a02481 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -340,7 +340,7 @@ static struct tag *last_tag;\n \n /* Input stream parsing */\n static whenspec_type whenspec = WHENSPEC_RAW;\n-static struct strbuf command_buf;\n+static struct strbuf command_buf = STRBUF_INIT;\n static int unread_command_buf;\n static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};\n static struct recent_command *cmd_tail = &cmd_hist;\n@@ -1638,17 +1638,15 @@ static void cmd_mark(void)\n \n static void *cmd_data (size_t *size)\n {\n-\tsize_t length;\n-\tchar *buffer;\n+\tstruct strbuf buffer = STRBUF_INIT;\n \n \tif (prefixcmp(command_buf.buf, \"data \"))\n \t\tdie(\"Expected 'data n' command, found: %s\", command_buf.buf);\n \n \tif (!prefixcmp(command_buf.buf + 5, \"<<\")) {\n \t\tchar *term = xstrdup(command_buf.buf + 5 + 2);\n-\t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n-\t\tlength = 0;\n-\t\tbuffer = xmalloc(sz);\n+\t\tsize_t term_len = command_buf.len - 5 - 2;\n+\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1656,21 +1654,18 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n-\t\t\tmemcpy(buffer + length,\n-\t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len);\n-\t\t\tlength += command_buf.len;\n-\t\t\tbuffer[length++] = '\\n';\n+\t\t\tstrbuf_addbuf(&buffer, &command_buf);\n+\t\t\tstrbuf_addch(&buffer, '\\n');\n \t\t}\n \t\tfree(term);\n \t}\n \telse {\n-\t\tsize_t n = 0;\n+\t\tsize_t n = 0, length;\n+\n \t\tlength = strtoul(command_buf.buf + 5, NULL, 10);\n-\t\tbuffer = xmalloc(length);\n+\n \t\twhile (n < length) {\n-\t\t\tsize_t s = fread(buffer + n, 1, length - n, stdin);\n+\t\t\tsize_t s = strbuf_fread(&buffer, length - n, stdin);\n \t\t\tif (!s && feof(stdin))\n \t\t\t\tdie(\"EOF in data (%lu bytes remaining)\",\n \t\t\t\t\t(unsigned long)(length - n));\n@@ -1679,8 +1674,8 @@ static void *cmd_data (size_t *size)\n \t}\n \n \tskip_optional_lf();\n-\t*size = length;\n-\treturn buffer;\n+\t*size = buffer.len;\n+\treturn strbuf_detach(&buffer);\n }\n \n static int validate_raw_date(const char *src, char *result, int maxlen)\n-- \n1.5.3\n"},{"id":"52472","messageId":"Pine.LNX.4.64.0709041642350.28586@racer.site","threadId":"9753","inReplyTo":"11889144741644-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-04T15:44:30Z","receivedAt":"2007-09-04T15:44:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 4 Sep 2007, Pierre Habouzit wrote:\n\n> +void strbuf_grow(struct strbuf *sb, size_t extra) {\n> +\tif (sb->len + extra + STRBUF_GROW_STEP < sb->len)\n> +\t\tdie(\"you want to use way to much memory\");\n> +\n> +\tsb->alloc = ((sb->len + extra) + STRBUF_GROW_STEP) & ~(STRBUF_GROW_STEP - 1);\n> +\tsb->buf   = xrealloc(sb->buf, sb->alloc);\n> +}\n\nWhy not use ALLOC_GROW()?  Seems to me more efficient than growing by 1kB \nblocks all the time, for big strings as for short strings.\n\nCiao,\nDscho\n"},{"id":"52477","messageId":"20070904161843.GB3381@artemis.corp","threadId":"9753","inReplyTo":"Pine.LNX.4.64.0709041642350.28586@racer.site","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-04T16:18:43Z","receivedAt":"2007-09-04T16:18:43Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Tue, Sep 04, 2007 at 03:44:30PM +0000, Johannes Schindelin wrote:\n> Hi,\n> \n> On Tue, 4 Sep 2007, Pierre Habouzit wrote:\n> \n> > +void strbuf_grow(struct strbuf *sb, size_t extra) {\n> > +\tif (sb->len + extra + STRBUF_GROW_STEP < sb->len)\n> > +\t\tdie(\"you want to use way to much memory\");\n> > +\n> > +\tsb->alloc = ((sb->len + extra) + STRBUF_GROW_STEP) & ~(STRBUF_GROW_STEP - 1);\n> > +\tsb->buf   = xrealloc(sb->buf, sb->alloc);\n> > +}\n> \n> Why not use ALLOC_GROW()?  Seems to me more efficient than growing by 1kB \n> blocks all the time, for big strings as for short strings.\n\n  ooooh, now I'm guilty of not knowing all git APIs very well yet :) Indeed,\nthis should just be:\n\n    void strbuf_grow(struct strbuf *sb, size_t extra) {\n        if (sb->len + extra + 1 < sb->len)\n            die(\"you want to use way to much memory\");\n        ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n    }\n\n  This is definitely better on so many levels !\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52489","messageId":"16188017-44C2-4854-8EF5-23271E8091BA@wincent.com","threadId":"9753","inReplyTo":"20070904161843.GB3381@artemis.corp","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-09-04T17:18:46Z","receivedAt":"2007-09-04T17:18:46Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 4/9/2007, a las 18:18, Pierre Habouzit escribió:\n\n>   ooooh, now I'm guilty of not knowing all git APIs very well  \n> yet :) Indeed,\n> this should just be:\n>\n>     void strbuf_grow(struct strbuf *sb, size_t extra) {\n>         if (sb->len + extra + 1 < sb->len)\n>             die(\"you want to use way to much memory\");\n>         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n>     }\n\n\"too much memory\", not \"to much memory\"\n\nCheers,\nWincent\n"},{"id":"52530","messageId":"46DDEE5F.8070800@lsrfire.ath.cx","threadId":"9753","inReplyTo":"11889144743483-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-09-04T23:46:39Z","receivedAt":"2007-09-04T23:46:39Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Pierre Habouzit schrieb:\n>   This is just cleaner way to deal with strbufs, using its API rather than\n> reinventing it in the module (e.g. strbuf_append_string is just the plain\n> strbuf_addstr function, and it was used to perform what strbuf_addch does\n> anyways).\n> ---\n>  archive-tar.c |   65 ++++++++++++++-------------------------------------------\n>  1 files changed, 16 insertions(+), 49 deletions(-)\n\nApart from the wrong subject I really like this patch. :-D\n\nThanks!\nRené\n"},{"id":"52531","messageId":"46DDEE73.5020904@lsrfire.ath.cx","threadId":"9753","inReplyTo":"11889144743483-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-09-04T23:46:59Z","receivedAt":"2007-09-04T23:46:59Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Pierre Habouzit schrieb:\n>   This is just cleaner way to deal with strbufs, using its API rather than\n> reinventing it in the module (e.g. strbuf_append_string is just the plain\n> strbuf_addstr function, and it was used to perform what strbuf_addch does\n> anyways).\n> ---\n>  archive-tar.c |   65 ++++++++++++++-------------------------------------------\n>  1 files changed, 16 insertions(+), 49 deletions(-)\n\nApart from the wrong subject line I really like this patch. :-D\n\nThanks!\nRené\n"},{"id":"52538","messageId":"buoabs1raaz.fsf@dhapc248.dev.necel.com","threadId":"9753","inReplyTo":"20070904115317.GA3381@artemis.corp","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Miles Bader","fromEmail":"miles.bader@necel.com","sentAt":"2007-09-05T04:44:04Z","receivedAt":"2007-09-05T04:44:04Z","isPatch":true,"sender":{"key":"miles.bader@necel.com","avatar":"https://gravatar.com/avatar/be062d4050eb88e04229cbdb60f803e1bd647923a015996c2439e76f23e336a7?d=mp&s=160"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n>   In my own coding rules, I have _new/_delete and _init/_wipe functions,\n> the former acts on pointers, the latter on the structs. Hence the\n> naming.\n\nA little off-topic, but my own personal convention for the latter case\nare _init/_fini -- I've always thought the \"fini\" name was a pretty good\npartner for \"init\", so I share it here... :-)\n\n-Miles\n\n-- \no The existentialist, not having a pillow, goes everywhere with the book by\n  Sullivan, _I am going to spit on your graves_.\n"},{"id":"52550","messageId":"20070905074815.GB31750@artemis.corp","threadId":"9753","inReplyTo":"46DDEE73.5020904@lsrfire.ath.cx","subject":"Re: [PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T07:48:15Z","receivedAt":"2007-09-05T07:48:15Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Tue, Sep 04, 2007 at 11:46:59PM +0000, René Scharfe wrote:\n> Pierre Habouzit schrieb:\n> >   This is just cleaner way to deal with strbufs, using its API rather than\n> > reinventing it in the module (e.g. strbuf_append_string is just the plain\n> > strbuf_addstr function, and it was used to perform what strbuf_addch does\n> > anyways).\n> > ---\n> >  archive-tar.c |   65 ++++++++++++++-------------------------------------------\n> >  1 files changed, 16 insertions(+), 49 deletions(-)\n> \n> Apart from the wrong subject line I really like this patch. :-D\n\n  oh boy, yes I fixed that in my local patch collection. I'm waiting for\na few hours (days ?) to see if there will be some more comments, I've\nintegrated every single one done here already (and some I had on IRC\ntoo), and I'll repost a new clean series that I intend to be a real\nproposal for inclusion.\n\n  And yes, this patch is a perfect example of the gain we have to share\na common buffer API. The code looks (at least to me) way nicer, and if\nyou look in the details, we perform as many memory allocations, copies,\nand so on as in the previous version.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52551","messageId":"7vodghk057.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"20070905074815.GB31750@artemis.corp","subject":"Re: [PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-05T08:05:24Z","receivedAt":"2007-09-05T08:05:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   oh boy, yes I fixed that in my local patch collection. I'm waiting for\n> a few hours (days ?) to see if there will be some more comments, I've\n> integrated every single one done here already (and some I had on IRC\n> too), and I'll repost a new clean series that I intend to be a real\n> proposal for inclusion.\n\nAh, I actually did the single trivial fix-up (ALLOC_GROW) and\nhave been looking at it, but I'll discard it.  Thanks.\n\n>   And yes, this patch is a perfect example of the gain we have to share\n> a common buffer API. The code looks (at least to me) way nicer, and if\n> you look in the details, we perform as many memory allocations, copies,\n> and so on as in the previous version.\n\nWait.  What is your point in saying this?  Is that a good thing\nto do \"as many\"?  \"API is cleaned-up and it is much easier to\nread but we do not do more than before\" is certainly a *BIG*\nplus, so perhaps that is what you meant, but when I first read\nit I thought you were saying \"we are not optimizing it at all\"\nin a negative sense.\n"},{"id":"52564","messageId":"20070905085720.GD31750@artemis.corp","threadId":"9753","inReplyTo":"7vodghk057.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T08:57:20Z","receivedAt":"2007-09-05T08:57:20Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Wed, Sep 05, 2007 at 08:05:24AM +0000, Junio C Hamano wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> >   oh boy, yes I fixed that in my local patch collection. I'm waiting for\n> > a few hours (days ?) to see if there will be some more comments, I've\n> > integrated every single one done here already (and some I had on IRC\n> > too), and I'll repost a new clean series that I intend to be a real\n> > proposal for inclusion.\n> \n> Ah, I actually did the single trivial fix-up (ALLOC_GROW) and\n> have been looking at it, but I'll discard it.  Thanks.\n\n  Yeah I integrated that as well already. I think I'll post the patches\nat the end of the Day (French Timezone so in 5 or 6 hours at least) to\nbe sure nobody has any good remarks to do first. If you want I can share\nmy branch somewhere if you want to look at it, just ask.\n\n> >   And yes, this patch is a perfect example of the gain we have to share\n> > a common buffer API. The code looks (at least to me) way nicer, and if\n> > you look in the details, we perform as many memory allocations, copies,\n> > and so on as in the previous version.\n> \n> Wait.  What is your point in saying this?  Is that a good thing\n> to do \"as many\"?  \"API is cleaned-up and it is much easier to\n> read but we do not do more than before\" is certainly a *BIG*\n> plus, so perhaps that is what you meant, but when I first read\n> it I thought you were saying \"we are not optimizing it at all\"\n> in a negative sense.\n\n  Sorry if I chose wrong words to say that, it is clearly a big plus ! I\nwrote it having in mind that very often abstractions and high level APIs\noften degrade performance. It does not, and that's a huge win. The point\nis that \"despite the somehow higher level API we don't loose an inch of\nperformance\".\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52617","messageId":"11890199232110-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"20070905085720.GD31750@artemis.corp","subject":"[PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:36Z","receivedAt":"2007-09-05T19:18:36Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  A strbuf can be used to store byte arrays, or as an extended string\nlibrary. The `buf' member can be passed to any C legacy string function,\nbecause strbuf operations always ensure there is a terminating \\0 at the end\nof the buffer, not accounted in the `len' field of the structure.\n\n  A strbuf can be used to generate a string/buffer whose final size is not\nreally known, and then \"strbuf_detach\" can be used to get the built buffer,\nand keep the wrapping \"strbuf\" structure usable for further work again.\n\n  Other interesting feature: strbuf_grow(sb, size) ensure that there is\nenough allocated space in `sb' to put `size' new octets of data in the\nbuffer. It helps avoiding reallocating data for nothing when the problem the\nstrbuf helps to solve has a known typical size.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n archive-tar.c |    2 +-\n fast-import.c |   15 ++++----\n mktree.c      |    4 +--\n strbuf.c      |  103 +++++++++++++++++++++++++++++++++++++++++++++++++--------\n strbuf.h      |   42 ++++++++++++++++++++++-\n 5 files changed, 138 insertions(+), 28 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 66fe3e3..a0763c5 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -166,7 +166,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \t\tsprintf(header.name, \"%s.paxheader\", sha1_to_hex(sha1));\n \t} else {\n \t\tif (verbose)\n-\t\t\tfprintf(stderr, \"%.*s\\n\", path->len, path->buf);\n+\t\t\tfprintf(stderr, \"%.*s\\n\", (int)path->len, path->buf);\n \t\tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n \t\t\t*header.typeflag = TYPEFLAG_DIR;\n \t\t\tmode = (mode | 0777) & ~tar_umask;\ndiff --git a/fast-import.c b/fast-import.c\nindex 078079d..2f7baf4 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1595,7 +1595,7 @@ static void read_next_command(void)\n \t\t} else {\n \t\t\tstruct recent_command *rc;\n \n-\t\t\tcommand_buf.buf = NULL;\n+\t\t\tstrbuf_detach(&command_buf);\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n \t\t\t\treturn;\n@@ -1649,7 +1649,6 @@ static void *cmd_data (size_t *size)\n \t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n \t\tlength = 0;\n \t\tbuffer = xmalloc(sz);\n-\t\tcommand_buf.buf = NULL;\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1657,11 +1656,11 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len, sz);\n+\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n \t\t\tmemcpy(buffer + length,\n \t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len - 1);\n-\t\t\tlength += command_buf.len - 1;\n+\t\t\t\tcommand_buf.len);\n+\t\t\tlength += command_buf.len;\n \t\t\tbuffer[length++] = '\\n';\n \t\t}\n \t\tfree(term);\n@@ -2101,7 +2100,7 @@ static void cmd_new_commit(void)\n \t}\n \n \t/* file_change* */\n-\twhile (!command_buf.eof && command_buf.len > 1) {\n+\twhile (!command_buf.eof && command_buf.len > 0) {\n \t\tif (!prefixcmp(command_buf.buf, \"M \"))\n \t\t\tfile_change_m(b);\n \t\telse if (!prefixcmp(command_buf.buf, \"D \"))\n@@ -2256,7 +2255,7 @@ static void cmd_reset_branch(void)\n \telse\n \t\tb = new_branch(sp);\n \tread_next_command();\n-\tif (!cmd_from(b) && command_buf.len > 1)\n+\tif (!cmd_from(b) && command_buf.len > 0)\n \t\tunread_command_buf = 1;\n }\n \n@@ -2273,7 +2272,7 @@ static void cmd_checkpoint(void)\n \n static void cmd_progress(void)\n {\n-\tfwrite(command_buf.buf, 1, command_buf.len - 1, stdout);\n+\tfwrite(command_buf.buf, 1, command_buf.len, stdout);\n \tfputc('\\n', stdout);\n \tfflush(stdout);\n \tskip_optional_lf();\ndiff --git a/mktree.c b/mktree.c\nindex d86dde8..86de5eb 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -92,7 +92,6 @@ int main(int ac, char **av)\n \n \tstrbuf_init(&sb);\n \twhile (1) {\n-\t\tint len;\n \t\tchar *ptr, *ntr;\n \t\tunsigned mode;\n \t\tenum object_type type;\n@@ -101,7 +100,6 @@ int main(int ac, char **av)\n \t\tread_line(&sb, stdin, line_termination);\n \t\tif (sb.eof)\n \t\t\tbreak;\n-\t\tlen = sb.len;\n \t\tptr = sb.buf;\n \t\t/* Input is non-recursive ls-tree output format\n \t\t * mode SP type SP sha1 TAB name\n@@ -111,7 +109,7 @@ int main(int ac, char **av)\n \t\t\tdie(\"input format error: %s\", sb.buf);\n \t\tptr = ntr + 1; /* type */\n \t\tntr = strchr(ptr, ' ');\n-\t\tif (!ntr || sb.buf + len <= ntr + 41 ||\n+\t\tif (!ntr || sb.buf + sb.len <= ntr + 40 ||\n \t\t    ntr[41] != '\\t' ||\n \t\t    get_sha1_hex(ntr + 1, sha1))\n \t\t\tdie(\"input format error: %s\", sb.buf);\ndiff --git a/strbuf.c b/strbuf.c\nindex e33d06b..7866fbe 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -2,40 +2,115 @@\n #include \"strbuf.h\"\n \n void strbuf_init(struct strbuf *sb) {\n-\tsb->buf = NULL;\n-\tsb->eof = sb->alloc = sb->len = 0;\n+\tmemset(sb, 0, sizeof(*sb));\n }\n \n-static void strbuf_begin(struct strbuf *sb) {\n+void strbuf_release(struct strbuf *sb) {\n \tfree(sb->buf);\n+\tmemset(sb, 0, sizeof(*sb));\n+}\n+\n+void strbuf_reset(struct strbuf *sb) {\n+\tif (sb->len)\n+\t\tsb->buf[sb->len = 0] = '\\0';\n+}\n+\n+char *strbuf_detach(struct strbuf *sb) {\n+\tchar *res = sb->buf;\n \tstrbuf_init(sb);\n+\treturn res;\n+}\n+\n+void strbuf_grow(struct strbuf *sb, size_t extra) {\n+\tif (sb->len + extra + 1 < sb->len)\n+\t\tdie(\"you want to use way too much memory\");\n+\tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n+}\n+\n+void strbuf_add(struct strbuf *sb, const void *data, size_t len) {\n+\tstrbuf_grow(sb, len);\n+\tmemcpy(sb->buf + sb->len, data, len);\n+\tsb->len += len;\n+\tsb->buf[sb->len] = '\\0';\n+}\n+\n+void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)\n+{\n+\tsize_t len;\n+\tva_list ap2;\n+\n+\tva_copy(ap2, ap);\n+\n+\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n+\tif (len < 0) {\n+\t\tlen = 0;\n+\t}\n+\tif (len >= sb->alloc - sb->len) {\n+\t\tstrbuf_grow(sb, len);\n+\t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap2);\n+\t\tif (len >= sb->alloc - sb->len) {\n+\t\t\tlen = sb->alloc - sb->len - 1;\n+\t\t}\n+\t}\n+\tsb->len = sb->len + len;\n+\tsb->buf[sb->len] = '\\0';\n }\n \n-static void inline strbuf_add(struct strbuf *sb, int ch) {\n-\tif (sb->alloc <= sb->len) {\n-\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n-\t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n+size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) {\n+\tsize_t res;\n+\n+\tstrbuf_grow(sb, size);\n+\tres = fread(sb->buf + sb->len, 1, size, f);\n+\tif (res > 0) {\n+\t\tsb->len += res;\n+\t\tsb->buf[sb->len] = '\\0';\n \t}\n-\tsb->buf[sb->len++] = ch;\n+\treturn res;\n }\n \n-static void strbuf_end(struct strbuf *sb) {\n-\tstrbuf_add(sb, 0);\n+ssize_t strbuf_read(struct strbuf *sb, int fd)\n+{\n+\tsize_t oldlen = sb->len;\n+\n+\tfor (;;) {\n+\t\tssize_t cnt;\n+\n+\t\tstrbuf_grow(sb, 8192);\n+\t\tcnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);\n+\t\tif (cnt < 0) {\n+\t\t\tsb->buf[sb->len = oldlen] = '\\0';\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (!cnt)\n+\t\t\tbreak;\n+\t\tsb->len += cnt;\n+\t}\n+\n+\tsb->buf[sb->len] = '\\0';\n+\treturn sb->len - oldlen;\n }\n \n void read_line(struct strbuf *sb, FILE *fp, int term) {\n \tint ch;\n-\tstrbuf_begin(sb);\n \tif (feof(fp)) {\n+\t\tstrbuf_release(sb);\n \t\tsb->eof = 1;\n \t\treturn;\n \t}\n+\n+\tstrbuf_reset(sb);\n \twhile ((ch = fgetc(fp)) != EOF) {\n \t\tif (ch == term)\n \t\t\tbreak;\n-\t\tstrbuf_add(sb, ch);\n+\t\tstrbuf_grow(sb, 1);\n+\t\tsb->buf[sb->len++] = ch;\n \t}\n-\tif (ch == EOF && sb->len == 0)\n+\tif (ch == EOF && sb->len == 0) {\n+\t\tstrbuf_release(sb);\n \t\tsb->eof = 1;\n-\tstrbuf_end(sb);\n+\t}\n+\n+\tstrbuf_grow(sb, 1);\n+\tsb->buf[sb->len] = '\\0';\n }\n+\ndiff --git a/strbuf.h b/strbuf.h\nindex 74cc012..db1e438 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -1,13 +1,51 @@\n #ifndef STRBUF_H\n #define STRBUF_H\n struct strbuf {\n-\tint alloc;\n-\tint len;\n+\tsize_t alloc;\n+\tsize_t len;\n \tint eof;\n \tchar *buf;\n };\n \n+#define STRBUF_INIT  { 0, 0, 0, NULL }\n+\n+/* strbuf life cycle */\n extern void strbuf_init(struct strbuf *);\n+extern void strbuf_release(struct strbuf *);\n+extern void strbuf_reset(struct strbuf *);\n+extern char *strbuf_detach(struct strbuf *);\n+\n+\n+extern void strbuf_grow(struct strbuf *, size_t);\n+extern void strbuf_add(struct strbuf *, const void *, size_t);\n+\n+static inline void strbuf_addstr(struct strbuf *sb, const char *s) {\n+\tstrbuf_add(sb, s, strlen(s));\n+}\n+static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {\n+\tstrbuf_add(sb, sb2->buf, sb2->len);\n+}\n+static inline void strbuf_addch(struct strbuf *sb, size_t c) {\n+\tstrbuf_grow(sb, 1);\n+\tsb->buf[sb->len++] = c;\n+\tsb->buf[sb->len] = '\\0';\n+}\n+\n+__attribute__((format(printf,2,0)))\n+extern void strbuf_addvf(struct strbuf *, const char *, va_list);\n+\n+static inline __attribute__((format(printf,2,3)))\n+void strbuf_addf(struct strbuf *sb, const char *fmt, ...) {\n+\tva_list ap;\n+\tva_start(ap, fmt);\n+\tstrbuf_addvf(sb, fmt, ap);\n+\tva_end(ap);\n+}\n+\n+\n+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n+extern ssize_t strbuf_read(struct strbuf *, int fd);\n+\n extern void read_line(struct strbuf *, FILE *, int);\n \n #endif /* STRBUF_H */\n-- \n1.5.3\n"},{"id":"52615","messageId":"11890199232128-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890199232110-git-send-email-madcoder@debian.org","subject":"[PATCH] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:37Z","receivedAt":"2007-09-05T19:18:37Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This is just cleaner way to deal with strbufs, using its API rather than\nreinventing it in the module (e.g. strbuf_append_string is just the plain\nstrbuf_addstr function, and it was used to perform what strbuf_addch does\nanyways).\n---\n archive-tar.c |   65 ++++++++++++++-------------------------------------------\n 1 files changed, 16 insertions(+), 49 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex a0763c5..c84d7c0 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -78,19 +78,6 @@ static void write_trailer(void)\n \t}\n }\n \n-static void strbuf_append_string(struct strbuf *sb, const char *s)\n-{\n-\tint slen = strlen(s);\n-\tint total = sb->len + slen;\n-\tif (total + 1 > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total + 1);\n-\t\tsb->alloc = total + 1;\n-\t}\n-\tmemcpy(sb->buf + sb->len, s, slen);\n-\tsb->len = total;\n-\tsb->buf[total] = '\\0';\n-}\n-\n /*\n  * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n  * the size of the whole string (including the %u), the first %s is the\n@@ -100,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n                                      const char *value, unsigned int valuelen)\n {\n-\tchar *p;\n-\tint len, total, tmp;\n+\tint len, tmp;\n \n \t/* \"%u %s=%s\\n\" */\n \tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n \tfor (tmp = len; tmp > 9; tmp /= 10)\n \t\tlen++;\n \n-\ttotal = sb->len + len;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\n-\tp = sb->buf;\n-\tp += sprintf(p, \"%u %s=\", len, keyword);\n-\tmemcpy(p, value, valuelen);\n-\tp += valuelen;\n-\t*p = '\\n';\n-\tsb->len = total;\n+\tstrbuf_grow(sb, len);\n+\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n+\tstrbuf_add(sb, value, valuelen);\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static unsigned int ustar_header_chksum(const struct ustar_header *header)\n@@ -153,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \tstruct strbuf ext_header;\n \n \tmemset(&header, 0, sizeof(header));\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\tstrbuf_init(&ext_header);\n \n \tif (!sha1) {\n \t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n@@ -225,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \n \tif (ext_header.len > 0) {\n \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n-\t\tfree(ext_header.buf);\n \t}\n+\tstrbuf_release(&ext_header);\n \twrite_blocked(&header, sizeof(header));\n \tif (S_ISREG(mode) && buffer && size > 0)\n \t\twrite_blocked(buffer, size);\n@@ -235,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n static void write_global_extended_header(const unsigned char *sha1)\n {\n \tstruct strbuf ext_header;\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\n+\tstrbuf_init(&ext_header);\n \tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n \twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n-\tfree(ext_header.buf);\n+\tstrbuf_release(&ext_header);\n }\n \n static int git_tar_config(const char *var, const char *value)\n@@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n                            const char *base, int baselen,\n                            const char *filename, unsigned mode, int stage)\n {\n-\tstatic struct strbuf path;\n+\tstatic struct strbuf path = STRBUF_INIT;\n \tint filenamelen = strlen(filename);\n \tvoid *buffer;\n \tenum object_type type;\n \tunsigned long size;\n \n-\tif (!path.alloc) {\n-\t\tpath.buf = xmalloc(PATH_MAX);\n-\t\tpath.alloc = PATH_MAX;\n-\t\tpath.len = path.eof = 0;\n-\t}\n-\tif (path.alloc < baselen + filenamelen + 1) {\n-\t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n-\t\tpath.alloc = baselen + filenamelen + 1;\n-\t}\n-\tmemcpy(path.buf, base, baselen);\n-\tmemcpy(path.buf + baselen, filename, filenamelen);\n-\tpath.len = baselen + filenamelen;\n-\tpath.buf[path.len] = '\\0';\n+\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n+\tstrbuf_reset(&path);\n+\tstrbuf_add(&path, base, baselen);\n+\tstrbuf_add(&path, filename, filenamelen);\n \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n-\t\tstrbuf_append_string(&path, \"/\");\n+\t\tstrbuf_addch(&path, '/');\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\n-- \n1.5.3\n"},{"id":"52618","messageId":"11890199232646-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890199232128-git-send-email-madcoder@debian.org","subject":"[PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:38Z","receivedAt":"2007-09-05T19:18:38Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This is just cleaner way to deal with strbufs, using its API rather than\nreinventing it in the module (e.g. strbuf_append_string is just the plain\nstrbuf_addstr function, and it was used to perform what strbuf_addch does\nanyways).\n---\n archive-tar.c |   65 ++++++++++++++-------------------------------------------\n 1 files changed, 16 insertions(+), 49 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex a0763c5..c84d7c0 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -78,19 +78,6 @@ static void write_trailer(void)\n \t}\n }\n \n-static void strbuf_append_string(struct strbuf *sb, const char *s)\n-{\n-\tint slen = strlen(s);\n-\tint total = sb->len + slen;\n-\tif (total + 1 > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total + 1);\n-\t\tsb->alloc = total + 1;\n-\t}\n-\tmemcpy(sb->buf + sb->len, s, slen);\n-\tsb->len = total;\n-\tsb->buf[total] = '\\0';\n-}\n-\n /*\n  * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n  * the size of the whole string (including the %u), the first %s is the\n@@ -100,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n                                      const char *value, unsigned int valuelen)\n {\n-\tchar *p;\n-\tint len, total, tmp;\n+\tint len, tmp;\n \n \t/* \"%u %s=%s\\n\" */\n \tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n \tfor (tmp = len; tmp > 9; tmp /= 10)\n \t\tlen++;\n \n-\ttotal = sb->len + len;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\n-\tp = sb->buf;\n-\tp += sprintf(p, \"%u %s=\", len, keyword);\n-\tmemcpy(p, value, valuelen);\n-\tp += valuelen;\n-\t*p = '\\n';\n-\tsb->len = total;\n+\tstrbuf_grow(sb, len);\n+\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n+\tstrbuf_add(sb, value, valuelen);\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static unsigned int ustar_header_chksum(const struct ustar_header *header)\n@@ -153,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \tstruct strbuf ext_header;\n \n \tmemset(&header, 0, sizeof(header));\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\tstrbuf_init(&ext_header);\n \n \tif (!sha1) {\n \t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n@@ -225,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \n \tif (ext_header.len > 0) {\n \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n-\t\tfree(ext_header.buf);\n \t}\n+\tstrbuf_release(&ext_header);\n \twrite_blocked(&header, sizeof(header));\n \tif (S_ISREG(mode) && buffer && size > 0)\n \t\twrite_blocked(buffer, size);\n@@ -235,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n static void write_global_extended_header(const unsigned char *sha1)\n {\n \tstruct strbuf ext_header;\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\n+\tstrbuf_init(&ext_header);\n \tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n \twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n-\tfree(ext_header.buf);\n+\tstrbuf_release(&ext_header);\n }\n \n static int git_tar_config(const char *var, const char *value)\n@@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n                            const char *base, int baselen,\n                            const char *filename, unsigned mode, int stage)\n {\n-\tstatic struct strbuf path;\n+\tstatic struct strbuf path = STRBUF_INIT;\n \tint filenamelen = strlen(filename);\n \tvoid *buffer;\n \tenum object_type type;\n \tunsigned long size;\n \n-\tif (!path.alloc) {\n-\t\tpath.buf = xmalloc(PATH_MAX);\n-\t\tpath.alloc = PATH_MAX;\n-\t\tpath.len = path.eof = 0;\n-\t}\n-\tif (path.alloc < baselen + filenamelen + 1) {\n-\t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n-\t\tpath.alloc = baselen + filenamelen + 1;\n-\t}\n-\tmemcpy(path.buf, base, baselen);\n-\tmemcpy(path.buf + baselen, filename, filenamelen);\n-\tpath.len = baselen + filenamelen;\n-\tpath.buf[path.len] = '\\0';\n+\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n+\tstrbuf_reset(&path);\n+\tstrbuf_add(&path, base, baselen);\n+\tstrbuf_add(&path, filename, filenamelen);\n \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n-\t\tstrbuf_append_string(&path, \"/\");\n+\t\tstrbuf_addch(&path, '/');\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\n-- \n1.5.3\n"},{"id":"52616","messageId":"1189019923740-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890199232646-git-send-email-madcoder@debian.org","subject":"[PATCH] Use proper strbuf API, and also simplify cmd_data code.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:39Z","receivedAt":"2007-09-05T19:18:39Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This patch features the use of strbuf_detach, and prevent the programmer\nto mess with allocation directly. The code is as efficent as before, just\nmore concise and more straightforward.\n---\n fast-import.c |   29 ++++++++++++-----------------\n 1 files changed, 12 insertions(+), 17 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2f7baf4..1a02481 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -340,7 +340,7 @@ static struct tag *last_tag;\n \n /* Input stream parsing */\n static whenspec_type whenspec = WHENSPEC_RAW;\n-static struct strbuf command_buf;\n+static struct strbuf command_buf = STRBUF_INIT;\n static int unread_command_buf;\n static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};\n static struct recent_command *cmd_tail = &cmd_hist;\n@@ -1638,17 +1638,15 @@ static void cmd_mark(void)\n \n static void *cmd_data (size_t *size)\n {\n-\tsize_t length;\n-\tchar *buffer;\n+\tstruct strbuf buffer = STRBUF_INIT;\n \n \tif (prefixcmp(command_buf.buf, \"data \"))\n \t\tdie(\"Expected 'data n' command, found: %s\", command_buf.buf);\n \n \tif (!prefixcmp(command_buf.buf + 5, \"<<\")) {\n \t\tchar *term = xstrdup(command_buf.buf + 5 + 2);\n-\t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n-\t\tlength = 0;\n-\t\tbuffer = xmalloc(sz);\n+\t\tsize_t term_len = command_buf.len - 5 - 2;\n+\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1656,21 +1654,18 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n-\t\t\tmemcpy(buffer + length,\n-\t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len);\n-\t\t\tlength += command_buf.len;\n-\t\t\tbuffer[length++] = '\\n';\n+\t\t\tstrbuf_addbuf(&buffer, &command_buf);\n+\t\t\tstrbuf_addch(&buffer, '\\n');\n \t\t}\n \t\tfree(term);\n \t}\n \telse {\n-\t\tsize_t n = 0;\n+\t\tsize_t n = 0, length;\n+\n \t\tlength = strtoul(command_buf.buf + 5, NULL, 10);\n-\t\tbuffer = xmalloc(length);\n+\n \t\twhile (n < length) {\n-\t\t\tsize_t s = fread(buffer + n, 1, length - n, stdin);\n+\t\t\tsize_t s = strbuf_fread(&buffer, length - n, stdin);\n \t\t\tif (!s && feof(stdin))\n \t\t\t\tdie(\"EOF in data (%lu bytes remaining)\",\n \t\t\t\t\t(unsigned long)(length - n));\n@@ -1679,8 +1674,8 @@ static void *cmd_data (size_t *size)\n \t}\n \n \tskip_optional_lf();\n-\t*size = length;\n-\treturn buffer;\n+\t*size = buffer.len;\n+\treturn strbuf_detach(&buffer);\n }\n \n static int validate_raw_date(const char *src, char *result, int maxlen)\n-- \n1.5.3\n"},{"id":"52614","messageId":"11890199233357-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"1189019923740-git-send-email-madcoder@debian.org","subject":"[PATCH] Simplify write_tree using strbuf's.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:40Z","receivedAt":"2007-09-05T19:18:40Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n mktree.c |   22 +++++++---------------\n 1 files changed, 7 insertions(+), 15 deletions(-)\n\ndiff --git a/mktree.c b/mktree.c\nindex 86de5eb..3d11ac3 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -44,30 +44,22 @@ static int ent_compare(const void *a_, const void *b_)\n \n static void write_tree(unsigned char *sha1)\n {\n-\tchar *buffer;\n-\tunsigned long size, offset;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tsize_t size;\n \tint i;\n \n \tqsort(entries, used, sizeof(*entries), ent_compare);\n \tfor (size = i = 0; i < used; i++)\n \t\tsize += 32 + entries[i]->len;\n-\tbuffer = xmalloc(size);\n-\toffset = 0;\n+\tstrbuf_grow(&buf, size);\n \n \tfor (i = 0; i < used; i++) {\n \t\tstruct treeent *ent = entries[i];\n-\n-\t\tif (offset + ent->len + 100 < size) {\n-\t\t\tsize = alloc_nr(offset + ent->len + 100);\n-\t\t\tbuffer = xrealloc(buffer, size);\n-\t\t}\n-\t\toffset += sprintf(buffer + offset, \"%o \", ent->mode);\n-\t\toffset += sprintf(buffer + offset, \"%s\", ent->name);\n-\t\tbuffer[offset++] = 0;\n-\t\thashcpy((unsigned char*)buffer + offset, ent->sha1);\n-\t\toffset += 20;\n+\t\tstrbuf_addf(&buf, \"%o %s%c\", ent->mode, ent->name, '\\0');\n+\t\tstrbuf_add(&buf, ent->sha1, 20);\n \t}\n-\twrite_sha1_file(buffer, offset, tree_type, sha1);\n+\n+\twrite_sha1_file(buf.buf, buf.len, tree_type, sha1);\n }\n \n static const char mktree_usage[] = \"git-mktree [-z]\";\n-- \n1.5.3\n"},{"id":"52619","messageId":"1189019923943-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890199233357-git-send-email-madcoder@debian.org","subject":"[PATCH] Further strbuf re-engineering.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:41Z","receivedAt":"2007-09-05T19:18:41Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n builtin-apply.c       |   29 ++++++-----------------\n builtin-blame.c       |   34 +++++++++-------------------\n builtin-commit-tree.c |   59 ++++++++++--------------------------------------\n diff.c                |   25 ++++++--------------\n 4 files changed, 40 insertions(+), 107 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 25b1447..4d8b270 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -12,6 +12,7 @@\n #include \"blob.h\"\n #include \"delta.h\"\n #include \"builtin.h\"\n+#include \"strbuf.h\"\n \n /*\n  *  --check turns on checking that the working tree matches the\n@@ -181,34 +182,20 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c\n \n static void *read_patch_file(int fd, unsigned long *sizep)\n {\n-\tunsigned long size = 0, alloc = CHUNKSIZE;\n-\tvoid *buffer = xmalloc(alloc);\n+\tstruct strbuf buf = STRBUF_INIT;\n \n-\tfor (;;) {\n-\t\tssize_t nr = alloc - size;\n-\t\tif (nr < 1024) {\n-\t\t\talloc += CHUNKSIZE;\n-\t\t\tbuffer = xrealloc(buffer, alloc);\n-\t\t\tnr = alloc - size;\n-\t\t}\n-\t\tnr = xread(fd, (char *) buffer + size, nr);\n-\t\tif (!nr)\n-\t\t\tbreak;\n-\t\tif (nr < 0)\n-\t\t\tdie(\"git-apply: read returned %s\", strerror(errno));\n-\t\tsize += nr;\n-\t}\n-\t*sizep = size;\n+\tif (strbuf_read(&buf, fd) < 0)\n+\t\tdie(\"git-apply: read returned %s\", strerror(errno));\n+\t*sizep = buf.len;\n \n \t/*\n \t * Make sure that we have some slop in the buffer\n \t * so that we can do speculative \"memcmp\" etc, and\n \t * see to it that it is NUL-filled.\n \t */\n-\tif (alloc < size + SLOP)\n-\t\tbuffer = xrealloc(buffer, size + SLOP);\n-\tmemset((char *) buffer + size, 0, SLOP);\n-\treturn buffer;\n+\tstrbuf_grow(&buf, SLOP);\n+\tmemset(buf.buf + buf.len, 0, SLOP);\n+\treturn strbuf_detach(&buf);\n }\n \n static unsigned long linelen(const char *buffer, unsigned long size)\ndiff --git a/builtin-blame.c b/builtin-blame.c\nindex dc88a95..c2d36a1 100644\n--- a/builtin-blame.c\n+++ b/builtin-blame.c\n@@ -18,6 +18,7 @@\n #include \"cache-tree.h\"\n #include \"path-list.h\"\n #include \"mailmap.h\"\n+#include \"strbuf.h\"\n \n static char blame_usage[] =\n \"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\\n\"\n@@ -2001,11 +2002,10 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \tstruct commit *commit;\n \tstruct origin *origin;\n \tunsigned char head_sha1[20];\n-\tchar *buf;\n+\tstruct strbuf buf = STRBUF_INIT;\n \tconst char *ident;\n \tint fd;\n \ttime_t now;\n-\tunsigned long fin_size;\n \tint size, len;\n \tstruct cache_entry *ce;\n \tunsigned mode;\n@@ -2026,6 +2026,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \tif (!contents_from || strcmp(\"-\", contents_from)) {\n \t\tstruct stat st;\n \t\tconst char *read_from;\n+\t\tunsigned long fin_size;\n \n \t\tif (contents_from) {\n \t\t\tif (stat(contents_from, &st) < 0)\n@@ -2038,19 +2039,19 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \t\t\tread_from = path;\n \t\t}\n \t\tfin_size = xsize_t(st.st_size);\n-\t\tbuf = xmalloc(fin_size+1);\n \t\tmode = canon_mode(st.st_mode);\n \t\tswitch (st.st_mode & S_IFMT) {\n \t\tcase S_IFREG:\n \t\t\tfd = open(read_from, O_RDONLY);\n \t\t\tif (fd < 0)\n \t\t\t\tdie(\"cannot open %s\", read_from);\n-\t\t\tif (read_in_full(fd, buf, fin_size) != fin_size)\n+\t\t\tif (strbuf_read(&buf, fd) != xsize_t(st.st_size))\n \t\t\t\tdie(\"cannot read %s\", read_from);\n \t\t\tbreak;\n \t\tcase S_IFLNK:\n-\t\t\tif (readlink(read_from, buf, fin_size+1) != fin_size)\n+\t\t\tif (readlink(read_from, buf.buf, buf.alloc) != fin_size)\n \t\t\t\tdie(\"cannot readlink %s\", read_from);\n+\t\t\tbuf.len = fin_size;\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tdie(\"unsupported file type %s\", read_from);\n@@ -2059,26 +2060,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \telse {\n \t\t/* Reading from stdin */\n \t\tcontents_from = \"standard input\";\n-\t\tbuf = NULL;\n-\t\tfin_size = 0;\n \t\tmode = 0;\n-\t\twhile (1) {\n-\t\t\tssize_t cnt = 8192;\n-\t\t\tbuf = xrealloc(buf, fin_size + cnt);\n-\t\t\tcnt = xread(0, buf + fin_size, cnt);\n-\t\t\tif (cnt < 0)\n-\t\t\t\tdie(\"read error %s from stdin\",\n-\t\t\t\t    strerror(errno));\n-\t\t\tif (!cnt)\n-\t\t\t\tbreak;\n-\t\t\tfin_size += cnt;\n-\t\t}\n-\t\tbuf = xrealloc(buf, fin_size + 1);\n+\t\tif (strbuf_read(&buf, 0) < 0)\n+\t\t\tdie(\"read error %s from stdin\", strerror(errno));\n \t}\n-\tbuf[fin_size] = 0;\n-\torigin->file.ptr = buf;\n-\torigin->file.size = fin_size;\n-\tpretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);\n+\torigin->file.ptr = buf.buf;\n+\torigin->file.size = buf.len;\n+\tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);\n \tcommit->util = origin;\n \n \t/*\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex ccbcbe3..ee74814 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -8,42 +8,13 @@\n #include \"tree.h\"\n #include \"builtin.h\"\n #include \"utf8.h\"\n+#include \"strbuf.h\"\n \n #define BLOCKING (1ul << 14)\n \n /*\n  * FIXME! Share the code with \"write-tree.c\"\n  */\n-static void init_buffer(char **bufp, unsigned int *sizep)\n-{\n-\t*bufp = xmalloc(BLOCKING);\n-\t*sizep = 0;\n-}\n-\n-static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)\n-{\n-\tchar one_line[2048];\n-\tva_list args;\n-\tint len;\n-\tunsigned long alloc, size, newsize;\n-\tchar *buf;\n-\n-\tva_start(args, fmt);\n-\tlen = vsnprintf(one_line, sizeof(one_line), fmt, args);\n-\tva_end(args);\n-\tsize = *sizep;\n-\tnewsize = size + len + 1;\n-\talloc = (size + 32767) & ~32767;\n-\tbuf = *bufp;\n-\tif (newsize > alloc) {\n-\t\talloc = (newsize + 32767) & ~32767;\n-\t\tbuf = xrealloc(buf, alloc);\n-\t\t*bufp = buf;\n-\t}\n-\t*sizep = newsize - 1;\n-\tmemcpy(buf + size, one_line, len);\n-}\n-\n static void check_valid(unsigned char *sha1, enum object_type expect)\n {\n \tenum object_type type = sha1_object_info(sha1, NULL);\n@@ -87,9 +58,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \tint parents = 0;\n \tunsigned char tree_sha1[20];\n \tunsigned char commit_sha1[20];\n-\tchar comment[1000];\n-\tchar *buffer;\n-\tunsigned int size;\n+\tstruct strbuf buffer = STRBUF_INIT;\n \tint encoding_is_utf8;\n \n \tgit_config(git_default_config);\n@@ -118,8 +87,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t/* Not having i18n.commitencoding is the same as having utf-8 */\n \tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n \n-\tinit_buffer(&buffer, &size);\n-\tadd_buffer(&buffer, &size, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\tstrbuf_grow(&buffer, 8192); /* should avoid reallocs for the headers */\n+\tstrbuf_addf(&buffer, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n \n \t/*\n \t * NOTE! This ordering means that the same exact tree merged with a\n@@ -127,26 +96,24 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t * if everything else stays the same.\n \t */\n \tfor (i = 0; i < parents; i++)\n-\t\tadd_buffer(&buffer, &size, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n+\t\tstrbuf_addf(&buffer, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n \n \t/* Person/date information */\n-\tadd_buffer(&buffer, &size, \"author %s\\n\", git_author_info(1));\n-\tadd_buffer(&buffer, &size, \"committer %s\\n\", git_committer_info(1));\n+\tstrbuf_addf(&buffer, \"author %s\\n\", git_author_info(1));\n+\tstrbuf_addf(&buffer, \"committer %s\\n\", git_committer_info(1));\n \tif (!encoding_is_utf8)\n-\t\tadd_buffer(&buffer, &size,\n-\t\t\t\t\"encoding %s\\n\", git_commit_encoding);\n-\tadd_buffer(&buffer, &size, \"\\n\");\n+\t\tstrbuf_addf(&buffer, \"encoding %s\\n\", git_commit_encoding);\n+\tstrbuf_addch(&buffer, '\\n');\n \n \t/* And add the comment */\n-\twhile (fgets(comment, sizeof(comment), stdin) != NULL)\n-\t\tadd_buffer(&buffer, &size, \"%s\", comment);\n+\tif (strbuf_read(&buffer, 0) < 0)\n+\t\tdie(\"git-commit-tree: read returned %s\", strerror(errno));\n \n \t/* And check the encoding */\n-\tbuffer[size] = '\\0';\n-\tif (encoding_is_utf8 && !is_utf8(buffer))\n+\tif (encoding_is_utf8 && !is_utf8(buffer.buf))\n \t\tfprintf(stderr, commit_utf8_warn);\n \n-\tif (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {\n+\tif (!write_sha1_file(buffer.buf, buffer.len, commit_type, commit_sha1)) {\n \t\tprintf(\"%s\\n\", sha1_to_hex(commit_sha1));\n \t\treturn 0;\n \t}\ndiff --git a/diff.c b/diff.c\nindex 0d30d05..05721f8 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -9,6 +9,7 @@\n #include \"xdiff-interface.h\"\n #include \"color.h\"\n #include \"attr.h\"\n+#include \"strbuf.h\"\n \n #ifdef NO_FAST_WORKING_DIRECTORY\n #define FAST_WORKING_DIRECTORY 0\n@@ -1546,25 +1547,15 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n static int populate_from_stdin(struct diff_filespec *s)\n {\n #define INCREMENT 1024\n-\tchar *buf;\n-\tunsigned long size;\n-\tssize_t got;\n-\n-\tsize = 0;\n-\tbuf = NULL;\n-\twhile (1) {\n-\t\tbuf = xrealloc(buf, size + INCREMENT);\n-\t\tgot = xread(0, buf + size, INCREMENT);\n-\t\tif (!got)\n-\t\t\tbreak; /* EOF */\n-\t\tif (got < 0)\n-\t\t\treturn error(\"error while reading from stdin %s\",\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tif (strbuf_read(&buf, 0) < 0)\n+\t\treturn error(\"error while reading from stdin %s\",\n \t\t\t\t     strerror(errno));\n-\t\tsize += got;\n-\t}\n+\n \ts->should_munmap = 0;\n-\ts->data = buf;\n-\ts->size = size;\n+\ts->size = buf.len;\n+\ts->data = strbuf_detach(&buf);\n \ts->should_free = 1;\n \treturn 0;\n }\n-- \n1.5.3\n"},{"id":"52620","messageId":"1189019923662-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"1189019923943-git-send-email-madcoder@debian.org","subject":"[PATCH] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:42Z","receivedAt":"2007-09-05T19:18:42Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n builtin-rerere.c |   53 +++++++++++++++--------------------------------------\n 1 files changed, 15 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin-rerere.c b/builtin-rerere.c\nindex 29d057c..2025004 100644\n--- a/builtin-rerere.c\n+++ b/builtin-rerere.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"path-list.h\"\n+#include \"strbuf.h\"\n #include \"xdiff/xdiff.h\"\n #include \"xdiff-interface.h\"\n \n@@ -66,38 +67,14 @@ static int write_rr(struct path_list *rr, int out_fd)\n \treturn commit_lock_file(&write_lock);\n }\n \n-struct buffer {\n-\tchar *ptr;\n-\tint nr, alloc;\n-};\n-\n-static void append_line(struct buffer *buffer, const char *line)\n-{\n-\tint len = strlen(line);\n-\n-\tif (buffer->nr + len > buffer->alloc) {\n-\t\tbuffer->alloc = alloc_nr(buffer->nr + len);\n-\t\tbuffer->ptr = xrealloc(buffer->ptr, buffer->alloc);\n-\t}\n-\tmemcpy(buffer->ptr + buffer->nr, line, len);\n-\tbuffer->nr += len;\n-}\n-\n-static void clear_buffer(struct buffer *buffer)\n-{\n-\tfree(buffer->ptr);\n-\tbuffer->ptr = NULL;\n-\tbuffer->nr = buffer->alloc = 0;\n-}\n-\n static int handle_file(const char *path,\n \t unsigned char *sha1, const char *output)\n {\n \tSHA_CTX ctx;\n \tchar buf[1024];\n \tint hunk = 0, hunk_no = 0;\n-\tstruct buffer minus = { NULL, 0, 0 }, plus = { NULL, 0, 0 };\n-\tstruct buffer *one = &minus, *two = &plus;\n+\tstruct strbuf minus = STRBUF_INIT, plus = STRBUF_INIT;\n+\tstruct strbuf *one = &minus, *two = &plus;\n \tFILE *f = fopen(path, \"r\");\n \tFILE *out;\n \n@@ -122,36 +99,36 @@ static int handle_file(const char *path,\n \t\telse if (!prefixcmp(buf, \"=======\"))\n \t\t\thunk = 2;\n \t\telse if (!prefixcmp(buf, \">>>>>>> \")) {\n-\t\t\tint one_is_longer = (one->nr > two->nr);\n-\t\t\tint common_len = one_is_longer ? two->nr : one->nr;\n-\t\t\tint cmp = memcmp(one->ptr, two->ptr, common_len);\n+\t\t\tint one_is_longer = (one->len > two->len);\n+\t\t\tint common_len = one_is_longer ? two->len : one->len;\n+\t\t\tint cmp = memcmp(one->buf, two->buf, common_len);\n \n \t\t\thunk_no++;\n \t\t\thunk = 0;\n \t\t\tif ((cmp > 0) || ((cmp == 0) && one_is_longer)) {\n-\t\t\t\tstruct buffer *swap = one;\n+\t\t\t\tstruct strbuf *swap = one;\n \t\t\t\tone = two;\n \t\t\t\ttwo = swap;\n \t\t\t}\n \t\t\tif (out) {\n \t\t\t\tfputs(\"<<<<<<<\\n\", out);\n-\t\t\t\tfwrite(one->ptr, one->nr, 1, out);\n+\t\t\t\tfwrite(one->buf, one->len, 1, out);\n \t\t\t\tfputs(\"=======\\n\", out);\n-\t\t\t\tfwrite(two->ptr, two->nr, 1, out);\n+\t\t\t\tfwrite(two->buf, two->len, 1, out);\n \t\t\t\tfputs(\">>>>>>>\\n\", out);\n \t\t\t}\n \t\t\tif (sha1) {\n-\t\t\t\tSHA1_Update(&ctx, one->ptr, one->nr);\n+\t\t\t\tSHA1_Update(&ctx, one->buf, one->len);\n \t\t\t\tSHA1_Update(&ctx, \"\\0\", 1);\n-\t\t\t\tSHA1_Update(&ctx, two->ptr, two->nr);\n+\t\t\t\tSHA1_Update(&ctx, two->buf, two->len);\n \t\t\t\tSHA1_Update(&ctx, \"\\0\", 1);\n \t\t\t}\n-\t\t\tclear_buffer(one);\n-\t\t\tclear_buffer(two);\n+\t\t\tstrbuf_release(one);\n+\t\t\tstrbuf_release(two);\n \t\t} else if (hunk == 1)\n-\t\t\tappend_line(one, buf);\n+\t\t\tstrbuf_addstr(one, buf);\n \t\telse if (hunk == 2)\n-\t\t\tappend_line(two, buf);\n+\t\t\tstrbuf_addstr(two, buf);\n \t\telse if (out)\n \t\t\tfputs(buf, out);\n \t}\n-- \n1.5.3\n"},{"id":"52621","messageId":"11890199231311-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"1189019923662-git-send-email-madcoder@debian.org","subject":"[PATCH] More strbuf uses in cache-tree.c.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:18:43Z","receivedAt":"2007-09-05T19:18:43Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Should even be marginally faster.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n cache-tree.c |   57 ++++++++++++++++++++-------------------------------------\n 1 files changed, 20 insertions(+), 37 deletions(-)\n\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 077f034..27ca062 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"strbuf.h\"\n #include \"tree.h\"\n #include \"cache-tree.h\"\n \n@@ -235,8 +236,7 @@ static int update_one(struct cache_tree *it,\n \t\t      int missing_ok,\n \t\t      int dryrun)\n {\n-\tunsigned long size, offset;\n-\tchar *buffer;\n+\tstruct strbuf buffer = STRBUF_INIT;\n \tint i;\n \n \tif (0 <= it->entry_count && has_sha1_file(it->sha1))\n@@ -293,9 +293,7 @@ static int update_one(struct cache_tree *it,\n \t/*\n \t * Then write out the tree object for this level.\n \t */\n-\tsize = 8192;\n-\tbuffer = xmalloc(size);\n-\toffset = 0;\n+\tstrbuf_grow(&buffer, 8192);\n \n \tfor (i = 0; i < entries; i++) {\n \t\tstruct cache_entry *ce = cache[i];\n@@ -332,15 +330,9 @@ static int update_one(struct cache_tree *it,\n \t\tif (!ce->ce_mode)\n \t\t\tcontinue; /* entry being removed */\n \n-\t\tif (size < offset + entlen + 100) {\n-\t\t\tsize = alloc_nr(offset + entlen + 100);\n-\t\t\tbuffer = xrealloc(buffer, size);\n-\t\t}\n-\t\toffset += sprintf(buffer + offset,\n-\t\t\t\t  \"%o %.*s\", mode, entlen, path + baselen);\n-\t\tbuffer[offset++] = 0;\n-\t\thashcpy((unsigned char*)buffer + offset, sha1);\n-\t\toffset += 20;\n+\t\tstrbuf_grow(&buffer, entlen + 100);\n+\t\tstrbuf_addf(&buffer, \"%o %.*s%c\", mode, entlen, path + baselen, '\\0');\n+\t\tstrbuf_add(&buffer, sha1, 20);\n \n #if DEBUG\n \t\tfprintf(stderr, \"cache-tree update-one %o %.*s\\n\",\n@@ -349,10 +341,10 @@ static int update_one(struct cache_tree *it,\n \t}\n \n \tif (dryrun)\n-\t\thash_sha1_file(buffer, offset, tree_type, it->sha1);\n+\t\thash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);\n \telse\n-\t\twrite_sha1_file(buffer, offset, tree_type, it->sha1);\n-\tfree(buffer);\n+\t\twrite_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);\n+\tstrbuf_release(&buffer);\n \tit->entry_count = i;\n #if DEBUG\n \tfprintf(stderr, \"cache-tree update-one (%d ent, %d subtree) %s\\n\",\n@@ -378,12 +370,10 @@ int cache_tree_update(struct cache_tree *it,\n \treturn 0;\n }\n \n-static void *write_one(struct cache_tree *it,\n+static void write_one(struct cache_tree *it,\n \t\t       char *path,\n \t\t       int pathlen,\n-\t\t       char *buffer,\n-\t\t       unsigned long *size,\n-\t\t       unsigned long *offset)\n+\t\t\t   struct strbuf *buffer)\n {\n \tint i;\n \n@@ -393,13 +383,9 @@ static void *write_one(struct cache_tree *it,\n \t * tree-sha1 (missing if invalid)\n \t * subtree_nr \"cache-tree\" entries for subtrees.\n \t */\n-\tif (*size < *offset + pathlen + 100) {\n-\t\t*size = alloc_nr(*offset + pathlen + 100);\n-\t\tbuffer = xrealloc(buffer, *size);\n-\t}\n-\t*offset += sprintf(buffer + *offset, \"%.*s%c%d %d\\n\",\n-\t\t\t   pathlen, path, 0,\n-\t\t\t   it->entry_count, it->subtree_nr);\n+\tstrbuf_grow(buffer, pathlen + 100);\n+\tstrbuf_add(buffer, path, pathlen);\n+\tstrbuf_addf(buffer, \"%c%d %d\\n\", 0, it->entry_count, it->subtree_nr);\n \n #if DEBUG\n \tif (0 <= it->entry_count)\n@@ -412,8 +398,7 @@ static void *write_one(struct cache_tree *it,\n #endif\n \n \tif (0 <= it->entry_count) {\n-\t\thashcpy((unsigned char*)buffer + *offset, it->sha1);\n-\t\t*offset += 20;\n+\t\tstrbuf_add(buffer, it->sha1, 20);\n \t}\n \tfor (i = 0; i < it->subtree_nr; i++) {\n \t\tstruct cache_tree_sub *down = it->down[i];\n@@ -423,21 +408,19 @@ static void *write_one(struct cache_tree *it,\n \t\t\t\t\t     prev->name, prev->namelen) <= 0)\n \t\t\t\tdie(\"fatal - unsorted cache subtree\");\n \t\t}\n-\t\tbuffer = write_one(down->cache_tree, down->name, down->namelen,\n-\t\t\t\t   buffer, size, offset);\n+\t\twrite_one(down->cache_tree, down->name, down->namelen, buffer);\n \t}\n-\treturn buffer;\n }\n \n void *cache_tree_write(struct cache_tree *root, unsigned long *size_p)\n {\n \tchar path[PATH_MAX];\n-\tunsigned long size = 8192;\n-\tchar *buffer = xmalloc(size);\n+\tstruct strbuf buffer = STRBUF_INIT;\n \n-\t*size_p = 0;\n \tpath[0] = 0;\n-\treturn write_one(root, path, 0, buffer, &size, size_p);\n+\twrite_one(root, path, 0, &buffer);\n+\t*size_p = buffer.len;\n+\treturn strbuf_detach(&buffer);\n }\n \n static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)\n-- \n1.5.3\n"},{"id":"52622","messageId":"20070905192105.GA28129@artemis.corp","threadId":"9753","inReplyTo":"11890199232646-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Simplify strbuf uses in fast-import.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-05T19:21:05Z","receivedAt":"2007-09-05T19:21:05Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Sorry, this one is a false positive :|\n  I should have been more careful.\n\nOn Wed, Sep 05, 2007 at 07:18:38PM +0000, Pierre Habouzit wrote:\n>   This is just cleaner way to deal with strbufs, using its API rather than\n> reinventing it in the module (e.g. strbuf_append_string is just the plain\n> strbuf_addstr function, and it was used to perform what strbuf_addch does\n> anyways).\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52719","messageId":"7vlkbkb0na.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"11890199232110-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-06T09:31:37Z","receivedAt":"2007-09-06T09:31:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   A strbuf can be used to store byte arrays, or as an extended string\n> library. The `buf' member can be passed to any C legacy string function,\n> because strbuf operations always ensure there is a terminating \\0 at the end\n> of the buffer, not accounted in the `len' field of the structure.\n>\n>   A strbuf can be used to generate a string/buffer whose final size is not\n> really known, and then \"strbuf_detach\" can be used to get the built buffer,\n> and keep the wrapping \"strbuf\" structure usable for further work again.\n>\n>   Other interesting feature: strbuf_grow(sb, size) ensure that there is\n> enough allocated space in `sb' to put `size' new octets of data in the\n> buffer. It helps avoiding reallocating data for nothing when the problem the\n> strbuf helps to solve has a known typical size.\n\n\"Rework API semantics\" needs to be accompanied with an API\ndescription, perhaps at the beginning of each externally\nvisible function.\n\nAlso the commit log message needs to explain what the old\nsemantics was and what the improved one is, to highlight the\nchanges needed to the callers.  Especially...\n\n> @@ -1657,11 +1656,11 @@ static void *cmd_data (size_t *size)\n>  \t\t\tif (term_len == command_buf.len\n>  \t\t\t\t&& !strcmp(term, command_buf.buf))\n>  \t\t\t\tbreak;\n> -\t\t\tALLOC_GROW(buffer, length + command_buf.len, sz);\n> +\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n>  \t\t\tmemcpy(buffer + length,\n>  \t\t\t\tcommand_buf.buf,\n> -\t\t\t\tcommand_buf.len - 1);\n> -\t\t\tlength += command_buf.len - 1;\n> +\t\t\t\tcommand_buf.len);\n> +\t\t\tlength += command_buf.len;\n>  \t\t\tbuffer[length++] = '\\n';\n>  \t\t}\n>  \t\tfree(term);\n\n... it is not all obvious why these off-by-one changes are\nneeded without such a description.  The other hunks in this\npatch to this file are all such changes.\n\n> -static void inline strbuf_add(struct strbuf *sb, int ch) {\n\n> +static inline void strbuf_addch(struct strbuf *sb, size_t c) {\n> +\tstrbuf_grow(sb, 1);\n> +\tsb->buf[sb->len++] = c;\n> +\tsb->buf[sb->len] = '\\0';\n> +}\n\nYou certainly did not mean size_t wide characters.\n"},{"id":"52722","messageId":"20070906094926.GC8451@artemis.corp","threadId":"9753","inReplyTo":"7vlkbkb0na.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T09:49:26Z","receivedAt":"2007-09-06T09:49:26Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 09:31:37AM +0000, Junio C Hamano wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> >   A strbuf can be used to store byte arrays, or as an extended string\n> > library. The `buf' member can be passed to any C legacy string function,\n> > because strbuf operations always ensure there is a terminating \\0 at the end\n> > of the buffer, not accounted in the `len' field of the structure.\n> >\n> >   A strbuf can be used to generate a string/buffer whose final size is not\n> > really known, and then \"strbuf_detach\" can be used to get the built buffer,\n> > and keep the wrapping \"strbuf\" structure usable for further work again.\n> >\n> >   Other interesting feature: strbuf_grow(sb, size) ensure that there is\n> > enough allocated space in `sb' to put `size' new octets of data in the\n> > buffer. It helps avoiding reallocating data for nothing when the problem the\n> > strbuf helps to solve has a known typical size.\n> \n> \"Rework API semantics\" needs to be accompanied with an API\n> description, perhaps at the beginning of each externally\n> visible function.\n> \n> Also the commit log message needs to explain what the old\n> semantics was and what the improved one is, to highlight the\n> changes needed to the callers.  Especially...\n> \n> > @@ -1657,11 +1656,11 @@ static void *cmd_data (size_t *size)\n> >  \t\t\tif (term_len == command_buf.len\n> >  \t\t\t\t&& !strcmp(term, command_buf.buf))\n> >  \t\t\t\tbreak;\n> > -\t\t\tALLOC_GROW(buffer, length + command_buf.len, sz);\n> > +\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n> >  \t\t\tmemcpy(buffer + length,\n> >  \t\t\t\tcommand_buf.buf,\n> > -\t\t\t\tcommand_buf.len - 1);\n> > -\t\t\tlength += command_buf.len - 1;\n> > +\t\t\t\tcommand_buf.len);\n> > +\t\t\tlength += command_buf.len;\n> >  \t\t\tbuffer[length++] = '\\n';\n> >  \t\t}\n> >  \t\tfree(term);\n> \n> .... it is not all obvious why these off-by-one changes are\n> needed without such a description.  The other hunks in this\n> patch to this file are all such changes.\n\n  Yes, as I suppose you know, but I state it here again so that\neverybody understands, before strbuf's were merely a byte array, not\nnecessarily NUL-terminated. Hence many parts of the code that wanted to\npass the buffer to str* functions had to manually insert a NUL, hence it\nwas accounted in the length of the buffer.\n\n  Now, we always have a NUL after the \"official\" end of the buffer, so\nit's not needed anymore. The off-by-ones are just that. The hunk you\nquote is one where git's code was messing with strbufs internals\ndirectly, so the ALLOC_GROW has to take the 1 octed needed to maintain\nthe internal invariant. Though, the patch after this one rewrites the\nhunk to use strbuf's API's.\n\n> \n> > -static void inline strbuf_add(struct strbuf *sb, int ch) {\n> \n> > +static inline void strbuf_addch(struct strbuf *sb, size_t c) {\n> > +\tstrbuf_grow(sb, 1);\n> > +\tsb->buf[sb->len++] = c;\n> > +\tsb->buf[sb->len] = '\\0';\n> > +}\n> \n> You certainly did not mean size_t wide characters.\n\n  Oh boy, now I've been red-handed of :%s/\\<int\\>/\\<size_t\\>/ :)\n\n  I'll repost a _clean_ patch series soon with those things fixed, and\nthe wrong overflow test (that should be a >= and not a >) as well, as we\ndiscussed it on IRC before.\n\n  Oh and FWIW I believe the details of the NUL always after the buffer\narray has to be in strbuf.h and not in the commit comment, maybe I'll\nput it in both to make everybody happy.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52726","messageId":"7vtzq89kky.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"11890199232110-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-06T10:03:57Z","receivedAt":"2007-09-06T10:03:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n> diff --git a/strbuf.c b/strbuf.c\n> ...\n> +void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)\n> +{\n> +\tsize_t len;\n> +\tva_list ap2;\n> +\n> +\tva_copy(ap2, ap);\n> +\n> +\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n> +\tif (len < 0) {\n> +\t\tlen = 0;\n> +\t}\n> +\tif (len >= sb->alloc - sb->len) {\n> +\t\tstrbuf_grow(sb, len);\n> +\t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap2);\n> +\t\tif (len >= sb->alloc - sb->len) {\n> +\t\t\tlen = sb->alloc - sb->len - 1;\n> +\t\t}\n> +\t}\n> +\tsb->len = sb->len + len;\n> +\tsb->buf[sb->len] = '\\0';\n>  }\n\nHmmmmm...  Didn't we recently had a patch that used va_copy()\nwhich was not available somewhere and was shot down?\n\nInstead of that nice inline strbuf_addf(), you may have to do\nsomething like:\n\n\tstrbuf_addf(..., fmt, ...) {\n                va_list ap;\n\n                va_start(ap, fmt);\n                len = vsnprintf(...);\n                va_end(ap);\n                if (len >= sb_avail(sb)) {\n                        strbuf_grow(sb, len);\n                        va_start(ap, fmt);\n                        len = vsnprintf(...);\n                        va_end(ap);\n                        if (len >= sb_avail(sb))\n                                gaah();\n                }\n\t\tsb->len += len;\n                sb->buf[sb->len] = '\\0';\n\t}\n\n\n> +ssize_t strbuf_read(struct strbuf *sb, int fd)\n> +{\n> +\tsize_t oldlen = sb->len;\n> +\n> +\tfor (;;) {\n> +\t\tssize_t cnt;\n> +\n> +\t\tstrbuf_grow(sb, 8192);\n> +\t\tcnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);\n> +\t\tif (cnt < 0) {\n> +\t\t\tsb->buf[sb->len = oldlen] = '\\0';\n\nAssignment inside array subscript is very hard to read.\nBesides, what's the error semantics?  On error, this behaves as\nif no bytes are read (i.e. partial read results in the initial\nround is lost forever)?\n"},{"id":"52730","messageId":"20070906102236.GE8451@artemis.corp","threadId":"9753","inReplyTo":"7vtzq89kky.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T10:22:36Z","receivedAt":"2007-09-06T10:22:36Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 10:03:57AM +0000, Junio C Hamano wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> > diff --git a/strbuf.c b/strbuf.c\n> > ...\n> > +void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)\n> > +{\n> > +\tsize_t len;\n> > +\tva_list ap2;\n> > +\n> > +\tva_copy(ap2, ap);\n> > +\n> > +\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n> > +\tif (len < 0) {\n> > +\t\tlen = 0;\n> > +\t}\n> > +\tif (len >= sb->alloc - sb->len) {\n> > +\t\tstrbuf_grow(sb, len);\n> > +\t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap2);\n> > +\t\tif (len >= sb->alloc - sb->len) {\n> > +\t\t\tlen = sb->alloc - sb->len - 1;\n> > +\t\t}\n> > +\t}\n> > +\tsb->len = sb->len + len;\n> > +\tsb->buf[sb->len] = '\\0';\n> >  }\n> \n> Hmmmmm...  Didn't we recently had a patch that used va_copy()\n> which was not available somewhere and was shot down?\n> \n> Instead of that nice inline strbuf_addf(), you may have to do\n> something like:\n> \n> \tstrbuf_addf(..., fmt, ...) {\n>                 va_list ap;\n> \n>                 va_start(ap, fmt);\n>                 len = vsnprintf(...);\n>                 va_end(ap);\n>                 if (len >= sb_avail(sb)) {\n>                         strbuf_grow(sb, len);\n>                         va_start(ap, fmt);\n>                         len = vsnprintf(...);\n>                         va_end(ap);\n>                         if (len >= sb_avail(sb))\n>                                 gaah();\n>                 }\n> \t\tsb->len += len;\n>                 sb->buf[sb->len] = '\\0';\n> \t}\n\n  I'll do that.\n\n> > +ssize_t strbuf_read(struct strbuf *sb, int fd)\n> > +{\n> > +\tsize_t oldlen = sb->len;\n> > +\n> > +\tfor (;;) {\n> > +\t\tssize_t cnt;\n> > +\n> > +\t\tstrbuf_grow(sb, 8192);\n> > +\t\tcnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);\n> > +\t\tif (cnt < 0) {\n> > +\t\t\tsb->buf[sb->len = oldlen] = '\\0';\n> \n> Assignment inside array subscript is very hard to read.\n> Besides, what's the error semantics?  On error, this behaves as\n> if no bytes are read (i.e. partial read results in the initial\n> round is lost forever)?\n\n  Yes that is the semantics, because it's how it was used everywhere in\ngit: either we were able to load all the data from the file descriptor,\nor weren't able to and the next thing we do is to die().\n\n  Maybe I should call the function strbuf_xread() instead ?\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52733","messageId":"11890776114037-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"20070902224213.GB431@artemis.corp","subject":"strbuf new API, take 2 for inclusion","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:04Z","receivedAt":"2007-09-06T11:20:04Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Here is a new patchset (with no wrong patchs and numbering this time)\nwith Junio's remarks integrated (the va_copy stuff, better documentation\nand patch comments and so on).\n\n  strbuf_read remains a \"I can read all the content of the file or the\ncaller is supposed to die()\" operation for now, as it's how it's used\nright now, this can be changed easily in the future if needs for it\nexists.\n\n  I've also stripped as many STRBUF_INIT uses as possible, some people\ndidn't liked it. I've kept its use for \"static\" strbufs where it's way\nmore convenient that a function call.\n"},{"id":"52738","messageId":"118907761140-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890776114037-git-send-email-madcoder@debian.org","subject":"[PATCH 1/7] Rework strbuf API and semantics.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:05Z","receivedAt":"2007-09-06T11:20:05Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  The gory details are explained in strbuf.h. The change of semantics this\npatch enforces is that the embeded buffer has always a '\\0' character after\nits last byte, to always make it a C-string. The offs-by-one changes are all\nrelated to that very change.\n\n  A strbuf can be used to store byte arrays, or as an extended string\nlibrary. The `buf' member can be passed to any C legacy string function,\nbecause strbuf operations always ensure there is a terminating \\0 at the end\nof the buffer, not accounted in the `len' field of the structure.\n\n  A strbuf can be used to generate a string/buffer whose final size is not\nreally known, and then \"strbuf_detach\" can be used to get the built buffer,\nand keep the wrapping \"strbuf\" structure usable for further work again.\n\n  Other interesting feature: strbuf_grow(sb, size) ensure that there is\nenough allocated space in `sb' to put `size' new octets of data in the\nbuffer. It helps avoiding reallocating data for nothing when the problem the\nstrbuf helps to solve has a known typical size.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n archive-tar.c |    2 +-\n fast-import.c |   15 ++++----\n mktree.c      |    4 +--\n strbuf.c      |  102 +++++++++++++++++++++++++++++++++++++++++++++++++--------\n strbuf.h      |   86 +++++++++++++++++++++++++++++++++++++++++++++++-\n 5 files changed, 181 insertions(+), 28 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 66fe3e3..a0763c5 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -166,7 +166,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \t\tsprintf(header.name, \"%s.paxheader\", sha1_to_hex(sha1));\n \t} else {\n \t\tif (verbose)\n-\t\t\tfprintf(stderr, \"%.*s\\n\", path->len, path->buf);\n+\t\t\tfprintf(stderr, \"%.*s\\n\", (int)path->len, path->buf);\n \t\tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n \t\t\t*header.typeflag = TYPEFLAG_DIR;\n \t\t\tmode = (mode | 0777) & ~tar_umask;\ndiff --git a/fast-import.c b/fast-import.c\nindex 078079d..2f7baf4 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1595,7 +1595,7 @@ static void read_next_command(void)\n \t\t} else {\n \t\t\tstruct recent_command *rc;\n \n-\t\t\tcommand_buf.buf = NULL;\n+\t\t\tstrbuf_detach(&command_buf);\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n \t\t\t\treturn;\n@@ -1649,7 +1649,6 @@ static void *cmd_data (size_t *size)\n \t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n \t\tlength = 0;\n \t\tbuffer = xmalloc(sz);\n-\t\tcommand_buf.buf = NULL;\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1657,11 +1656,11 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len, sz);\n+\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n \t\t\tmemcpy(buffer + length,\n \t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len - 1);\n-\t\t\tlength += command_buf.len - 1;\n+\t\t\t\tcommand_buf.len);\n+\t\t\tlength += command_buf.len;\n \t\t\tbuffer[length++] = '\\n';\n \t\t}\n \t\tfree(term);\n@@ -2101,7 +2100,7 @@ static void cmd_new_commit(void)\n \t}\n \n \t/* file_change* */\n-\twhile (!command_buf.eof && command_buf.len > 1) {\n+\twhile (!command_buf.eof && command_buf.len > 0) {\n \t\tif (!prefixcmp(command_buf.buf, \"M \"))\n \t\t\tfile_change_m(b);\n \t\telse if (!prefixcmp(command_buf.buf, \"D \"))\n@@ -2256,7 +2255,7 @@ static void cmd_reset_branch(void)\n \telse\n \t\tb = new_branch(sp);\n \tread_next_command();\n-\tif (!cmd_from(b) && command_buf.len > 1)\n+\tif (!cmd_from(b) && command_buf.len > 0)\n \t\tunread_command_buf = 1;\n }\n \n@@ -2273,7 +2272,7 @@ static void cmd_checkpoint(void)\n \n static void cmd_progress(void)\n {\n-\tfwrite(command_buf.buf, 1, command_buf.len - 1, stdout);\n+\tfwrite(command_buf.buf, 1, command_buf.len, stdout);\n \tfputc('\\n', stdout);\n \tfflush(stdout);\n \tskip_optional_lf();\ndiff --git a/mktree.c b/mktree.c\nindex d86dde8..86de5eb 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -92,7 +92,6 @@ int main(int ac, char **av)\n \n \tstrbuf_init(&sb);\n \twhile (1) {\n-\t\tint len;\n \t\tchar *ptr, *ntr;\n \t\tunsigned mode;\n \t\tenum object_type type;\n@@ -101,7 +100,6 @@ int main(int ac, char **av)\n \t\tread_line(&sb, stdin, line_termination);\n \t\tif (sb.eof)\n \t\t\tbreak;\n-\t\tlen = sb.len;\n \t\tptr = sb.buf;\n \t\t/* Input is non-recursive ls-tree output format\n \t\t * mode SP type SP sha1 TAB name\n@@ -111,7 +109,7 @@ int main(int ac, char **av)\n \t\t\tdie(\"input format error: %s\", sb.buf);\n \t\tptr = ntr + 1; /* type */\n \t\tntr = strchr(ptr, ' ');\n-\t\tif (!ntr || sb.buf + len <= ntr + 41 ||\n+\t\tif (!ntr || sb.buf + sb.len <= ntr + 40 ||\n \t\t    ntr[41] != '\\t' ||\n \t\t    get_sha1_hex(ntr + 1, sha1))\n \t\t\tdie(\"input format error: %s\", sb.buf);\ndiff --git a/strbuf.c b/strbuf.c\nindex e33d06b..acc7fc8 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -2,40 +2,114 @@\n #include \"strbuf.h\"\n \n void strbuf_init(struct strbuf *sb) {\n-\tsb->buf = NULL;\n-\tsb->eof = sb->alloc = sb->len = 0;\n+\tmemset(sb, 0, sizeof(*sb));\n }\n \n-static void strbuf_begin(struct strbuf *sb) {\n+void strbuf_release(struct strbuf *sb) {\n \tfree(sb->buf);\n+\tmemset(sb, 0, sizeof(*sb));\n+}\n+\n+void strbuf_reset(struct strbuf *sb) {\n+\tif (sb->len)\n+\t\tstrbuf_setlen(sb, 0);\n+\tsb->eof = 0;\n+}\n+\n+char *strbuf_detach(struct strbuf *sb) {\n+\tchar *res = sb->buf;\n \tstrbuf_init(sb);\n+\treturn res;\n+}\n+\n+void strbuf_grow(struct strbuf *sb, size_t extra) {\n+\tif (sb->len + extra + 1 <= sb->len)\n+\t\tdie(\"you want to use way too much memory\");\n+\tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n }\n \n-static void inline strbuf_add(struct strbuf *sb, int ch) {\n-\tif (sb->alloc <= sb->len) {\n-\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n-\t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n+void strbuf_add(struct strbuf *sb, const void *data, size_t len) {\n+\tstrbuf_grow(sb, len);\n+\tmemcpy(sb->buf + sb->len, data, len);\n+\tstrbuf_setlen(sb, sb->len + len);\n+}\n+\n+void strbuf_addf(struct strbuf *sb, const char *fmt, ...) {\n+\tint len;\n+\tva_list ap;\n+\n+\tva_start(ap, fmt);\n+\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n+\tva_end(ap);\n+\tif (len < 0) {\n+\t\tlen = 0;\n \t}\n-\tsb->buf[sb->len++] = ch;\n+\tif (len >= strbuf_avail(sb)) {\n+\t\tstrbuf_grow(sb, len);\n+\t\tva_start(ap, fmt);\n+\t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n+\t\tva_end(ap);\n+\t\tif (len >= strbuf_avail(sb)) {\n+\t\t\tdie(\"this should not happen, your snprintf is broken\");\n+\t\t}\n+\t}\n+\tstrbuf_setlen(sb, sb->len + len);\n }\n \n-static void strbuf_end(struct strbuf *sb) {\n-\tstrbuf_add(sb, 0);\n+size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) {\n+\tsize_t res;\n+\n+\tstrbuf_grow(sb, size);\n+\tres = fread(sb->buf + sb->len, 1, size, f);\n+\tif (res > 0) {\n+\t\tstrbuf_setlen(sb, sb->len + res);\n+\t}\n+\treturn res;\n+}\n+\n+ssize_t strbuf_read(struct strbuf *sb, int fd)\n+{\n+\tsize_t oldlen = sb->len;\n+\n+\tfor (;;) {\n+\t\tssize_t cnt;\n+\n+\t\tstrbuf_grow(sb, 8192);\n+\t\tcnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);\n+\t\tif (cnt < 0) {\n+\t\t\tstrbuf_setlen(sb, oldlen);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (!cnt)\n+\t\t\tbreak;\n+\t\tsb->len += cnt;\n+\t}\n+\n+\tsb->buf[sb->len] = '\\0';\n+\treturn sb->len - oldlen;\n }\n \n void read_line(struct strbuf *sb, FILE *fp, int term) {\n \tint ch;\n-\tstrbuf_begin(sb);\n \tif (feof(fp)) {\n+\t\tstrbuf_release(sb);\n \t\tsb->eof = 1;\n \t\treturn;\n \t}\n+\n+\tstrbuf_reset(sb);\n \twhile ((ch = fgetc(fp)) != EOF) {\n \t\tif (ch == term)\n \t\t\tbreak;\n-\t\tstrbuf_add(sb, ch);\n+\t\tstrbuf_grow(sb, 1);\n+\t\tsb->buf[sb->len++] = ch;\n \t}\n-\tif (ch == EOF && sb->len == 0)\n+\tif (ch == EOF && sb->len == 0) {\n+\t\tstrbuf_release(sb);\n \t\tsb->eof = 1;\n-\tstrbuf_end(sb);\n+\t}\n+\n+\tstrbuf_grow(sb, 1);\n+\tsb->buf[sb->len] = '\\0';\n }\n+\ndiff --git a/strbuf.h b/strbuf.h\nindex 74cc012..b40dc99 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -1,13 +1,95 @@\n #ifndef STRBUF_H\n #define STRBUF_H\n+\n+/*\n+ * Strbuf's can be use in many ways: as a byte array, or to store arbitrary\n+ * long, overflow safe strings.\n+ *\n+ * Strbufs has some invariants that are very important to keep in mind:\n+ *\n+ * 1. the ->buf member is always malloc-ed, hence strbuf's can be used to\n+ *    build complex strings/buffers whose final size isn't easily known.\n+ *\n+ *    It is legal to copy the ->buf pointer away. Though if you want to reuse\n+ *    the strbuf after that, setting ->buf to NULL isn't legal.\n+ *    `strbuf_detach' is the operation that detachs a buffer from its shell\n+ *    while keeping the shell valid wrt its invariants.\n+ *\n+ * 2. the ->buf member is a byte array that has at least ->len + 1 bytes\n+ *    allocated. The extra byte is used to store a '\\0', allowing the ->buf\n+ *    member to be a valid C-string. Every strbuf function ensure this\n+ *    invariant is preserved.\n+ *\n+ *    Note that it is OK to \"play\" with the buffer directly if you work it\n+ *    that way:\n+ *\n+ *    strbuf_grow(sb, SOME_SIZE);\n+ *    // ... here the memory areay starting at sb->buf, and of length\n+ *    // sb_avail(sb) is all yours, and you are sure that sb_avail(sb) is at\n+ *    // least SOME_SIZE\n+ *    strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);\n+ *\n+ *    Of course, SOME_OTHER_SIZE must be smaller or equal to sb_avail(sb).\n+ *\n+ *    Doing so is safe, though if it has to be done in many places, adding the\n+ *    missing API to the strbuf module is the way to go.\n+ *\n+ *    XXX: do _not_ assume that the area that is yours is of size ->alloc - 1\n+ *         even if it's true in the current implementation. Alloc is somehow a\n+ *         \"private\" member that should not be messed with.\n+ */\n+\n+#include <assert.h>\n+\n struct strbuf {\n-\tint alloc;\n-\tint len;\n+\tsize_t alloc;\n+\tsize_t len;\n \tint eof;\n \tchar *buf;\n };\n \n+#define STRBUF_INIT  { 0, 0, 0, NULL }\n+\n+/*----- strbuf life cycle -----*/\n extern void strbuf_init(struct strbuf *);\n+extern void strbuf_release(struct strbuf *);\n+extern void strbuf_reset(struct strbuf *);\n+extern char *strbuf_detach(struct strbuf *);\n+\n+/*----- strbuf size related -----*/\n+static inline size_t strbuf_avail(struct strbuf *sb) {\n+    return sb->alloc ? sb->alloc - sb->len - 1 : 0;\n+}\n+static inline void strbuf_setlen(struct strbuf *sb, size_t len) {\n+    assert (len < sb->alloc);\n+    sb->len = len;\n+    sb->buf[len] = '\\0';\n+}\n+\n+extern void strbuf_grow(struct strbuf *, size_t);\n+\n+/*----- add data in your buffer -----*/\n+static inline void strbuf_addch(struct strbuf *sb, int c) {\n+\tstrbuf_grow(sb, 1);\n+\tsb->buf[sb->len++] = c;\n+\tsb->buf[sb->len] = '\\0';\n+}\n+\n+extern void strbuf_add(struct strbuf *, const void *, size_t);\n+static inline void strbuf_addstr(struct strbuf *sb, const char *s) {\n+\tstrbuf_add(sb, s, strlen(s));\n+}\n+static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {\n+\tstrbuf_add(sb, sb2->buf, sb2->len);\n+}\n+\n+__attribute__((format(printf,2,3)))\n+extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n+\n+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n+/* XXX: if read fails, any partial read is undone */\n+extern ssize_t strbuf_read(struct strbuf *, int fd);\n+\n extern void read_line(struct strbuf *, FILE *, int);\n \n #endif /* STRBUF_H */\n-- \n1.5.3.1\n"},{"id":"52735","messageId":"11890776111843-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"118907761140-git-send-email-madcoder@debian.org","subject":"[PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:06Z","receivedAt":"2007-09-06T11:20:06Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This is just cleaner way to deal with strbufs, using its API rather than\nreinventing it in the module (e.g. strbuf_append_string is just the plain\nstrbuf_addstr function, and it was used to perform what strbuf_addch does\nanyways).\n---\n archive-tar.c |   65 ++++++++++++++-------------------------------------------\n 1 files changed, 16 insertions(+), 49 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex a0763c5..c84d7c0 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -78,19 +78,6 @@ static void write_trailer(void)\n \t}\n }\n \n-static void strbuf_append_string(struct strbuf *sb, const char *s)\n-{\n-\tint slen = strlen(s);\n-\tint total = sb->len + slen;\n-\tif (total + 1 > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total + 1);\n-\t\tsb->alloc = total + 1;\n-\t}\n-\tmemcpy(sb->buf + sb->len, s, slen);\n-\tsb->len = total;\n-\tsb->buf[total] = '\\0';\n-}\n-\n /*\n  * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n  * the size of the whole string (including the %u), the first %s is the\n@@ -100,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n                                      const char *value, unsigned int valuelen)\n {\n-\tchar *p;\n-\tint len, total, tmp;\n+\tint len, tmp;\n \n \t/* \"%u %s=%s\\n\" */\n \tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n \tfor (tmp = len; tmp > 9; tmp /= 10)\n \t\tlen++;\n \n-\ttotal = sb->len + len;\n-\tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n-\t}\n-\n-\tp = sb->buf;\n-\tp += sprintf(p, \"%u %s=\", len, keyword);\n-\tmemcpy(p, value, valuelen);\n-\tp += valuelen;\n-\t*p = '\\n';\n-\tsb->len = total;\n+\tstrbuf_grow(sb, len);\n+\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n+\tstrbuf_add(sb, value, valuelen);\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static unsigned int ustar_header_chksum(const struct ustar_header *header)\n@@ -153,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \tstruct strbuf ext_header;\n \n \tmemset(&header, 0, sizeof(header));\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\tstrbuf_init(&ext_header);\n \n \tif (!sha1) {\n \t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n@@ -225,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n \n \tif (ext_header.len > 0) {\n \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n-\t\tfree(ext_header.buf);\n \t}\n+\tstrbuf_release(&ext_header);\n \twrite_blocked(&header, sizeof(header));\n \tif (S_ISREG(mode) && buffer && size > 0)\n \t\twrite_blocked(buffer, size);\n@@ -235,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n static void write_global_extended_header(const unsigned char *sha1)\n {\n \tstruct strbuf ext_header;\n-\text_header.buf = NULL;\n-\text_header.len = ext_header.alloc = 0;\n+\n+\tstrbuf_init(&ext_header);\n \tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n \twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n-\tfree(ext_header.buf);\n+\tstrbuf_release(&ext_header);\n }\n \n static int git_tar_config(const char *var, const char *value)\n@@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n                            const char *base, int baselen,\n                            const char *filename, unsigned mode, int stage)\n {\n-\tstatic struct strbuf path;\n+\tstatic struct strbuf path = STRBUF_INIT;\n \tint filenamelen = strlen(filename);\n \tvoid *buffer;\n \tenum object_type type;\n \tunsigned long size;\n \n-\tif (!path.alloc) {\n-\t\tpath.buf = xmalloc(PATH_MAX);\n-\t\tpath.alloc = PATH_MAX;\n-\t\tpath.len = path.eof = 0;\n-\t}\n-\tif (path.alloc < baselen + filenamelen + 1) {\n-\t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n-\t\tpath.alloc = baselen + filenamelen + 1;\n-\t}\n-\tmemcpy(path.buf, base, baselen);\n-\tmemcpy(path.buf + baselen, filename, filenamelen);\n-\tpath.len = baselen + filenamelen;\n-\tpath.buf[path.len] = '\\0';\n+\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n+\tstrbuf_reset(&path);\n+\tstrbuf_add(&path, base, baselen);\n+\tstrbuf_add(&path, filename, filenamelen);\n \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n-\t\tstrbuf_append_string(&path, \"/\");\n+\t\tstrbuf_addch(&path, '/');\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\n-- \n1.5.3.1\n"},{"id":"52736","messageId":"11890776112292-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890776111843-git-send-email-madcoder@debian.org","subject":"[PATCH 3/7] Use proper strbuf API, and also simplify cmd_data code.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:07Z","receivedAt":"2007-09-06T11:20:07Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  This patch features the use of strbuf_detach, and prevent the programmer\nto mess with allocation directly. The code is as efficent as before, just\nmore concise and more straightforward.\n---\n fast-import.c |   30 +++++++++++++-----------------\n 1 files changed, 13 insertions(+), 17 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2f7baf4..74ff0fd 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -340,7 +340,7 @@ static struct tag *last_tag;\n \n /* Input stream parsing */\n static whenspec_type whenspec = WHENSPEC_RAW;\n-static struct strbuf command_buf;\n+static struct strbuf command_buf = STRBUF_INIT;\n static int unread_command_buf;\n static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};\n static struct recent_command *cmd_tail = &cmd_hist;\n@@ -1638,17 +1638,16 @@ static void cmd_mark(void)\n \n static void *cmd_data (size_t *size)\n {\n-\tsize_t length;\n-\tchar *buffer;\n+\tstruct strbuf buffer;\n \n+\tstrbuf_init(&buffer);\n \tif (prefixcmp(command_buf.buf, \"data \"))\n \t\tdie(\"Expected 'data n' command, found: %s\", command_buf.buf);\n \n \tif (!prefixcmp(command_buf.buf + 5, \"<<\")) {\n \t\tchar *term = xstrdup(command_buf.buf + 5 + 2);\n-\t\tsize_t sz = 8192, term_len = command_buf.len - 5 - 2;\n-\t\tlength = 0;\n-\t\tbuffer = xmalloc(sz);\n+\t\tsize_t term_len = command_buf.len - 5 - 2;\n+\n \t\tfor (;;) {\n \t\t\tread_line(&command_buf, stdin, '\\n');\n \t\t\tif (command_buf.eof)\n@@ -1656,21 +1655,18 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tALLOC_GROW(buffer, length + command_buf.len + 1, sz);\n-\t\t\tmemcpy(buffer + length,\n-\t\t\t\tcommand_buf.buf,\n-\t\t\t\tcommand_buf.len);\n-\t\t\tlength += command_buf.len;\n-\t\t\tbuffer[length++] = '\\n';\n+\t\t\tstrbuf_addbuf(&buffer, &command_buf);\n+\t\t\tstrbuf_addch(&buffer, '\\n');\n \t\t}\n \t\tfree(term);\n \t}\n \telse {\n-\t\tsize_t n = 0;\n+\t\tsize_t n = 0, length;\n+\n \t\tlength = strtoul(command_buf.buf + 5, NULL, 10);\n-\t\tbuffer = xmalloc(length);\n+\n \t\twhile (n < length) {\n-\t\t\tsize_t s = fread(buffer + n, 1, length - n, stdin);\n+\t\t\tsize_t s = strbuf_fread(&buffer, length - n, stdin);\n \t\t\tif (!s && feof(stdin))\n \t\t\t\tdie(\"EOF in data (%lu bytes remaining)\",\n \t\t\t\t\t(unsigned long)(length - n));\n@@ -1679,8 +1675,8 @@ static void *cmd_data (size_t *size)\n \t}\n \n \tskip_optional_lf();\n-\t*size = length;\n-\treturn buffer;\n+\t*size = buffer.len;\n+\treturn strbuf_detach(&buffer);\n }\n \n static int validate_raw_date(const char *src, char *result, int maxlen)\n-- \n1.5.3.1\n"},{"id":"52734","messageId":"11890776111670-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890776112292-git-send-email-madcoder@debian.org","subject":"[PATCH 4/7] Simplify write_tree using strbuf's.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:08Z","receivedAt":"2007-09-06T11:20:08Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n mktree.c |   23 ++++++++---------------\n 1 files changed, 8 insertions(+), 15 deletions(-)\n\ndiff --git a/mktree.c b/mktree.c\nindex 86de5eb..2e84889 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -44,30 +44,23 @@ static int ent_compare(const void *a_, const void *b_)\n \n static void write_tree(unsigned char *sha1)\n {\n-\tchar *buffer;\n-\tunsigned long size, offset;\n+\tstruct strbuf buf;\n+\tsize_t size;\n \tint i;\n \n \tqsort(entries, used, sizeof(*entries), ent_compare);\n \tfor (size = i = 0; i < used; i++)\n \t\tsize += 32 + entries[i]->len;\n-\tbuffer = xmalloc(size);\n-\toffset = 0;\n+\tstrbuf_init(&buf);\n+\tstrbuf_grow(&buf, size);\n \n \tfor (i = 0; i < used; i++) {\n \t\tstruct treeent *ent = entries[i];\n-\n-\t\tif (offset + ent->len + 100 < size) {\n-\t\t\tsize = alloc_nr(offset + ent->len + 100);\n-\t\t\tbuffer = xrealloc(buffer, size);\n-\t\t}\n-\t\toffset += sprintf(buffer + offset, \"%o \", ent->mode);\n-\t\toffset += sprintf(buffer + offset, \"%s\", ent->name);\n-\t\tbuffer[offset++] = 0;\n-\t\thashcpy((unsigned char*)buffer + offset, ent->sha1);\n-\t\toffset += 20;\n+\t\tstrbuf_addf(&buf, \"%o %s%c\", ent->mode, ent->name, '\\0');\n+\t\tstrbuf_add(&buf, ent->sha1, 20);\n \t}\n-\twrite_sha1_file(buffer, offset, tree_type, sha1);\n+\n+\twrite_sha1_file(buf.buf, buf.len, tree_type, sha1);\n }\n \n static const char mktree_usage[] = \"git-mktree [-z]\";\n-- \n1.5.3.1\n"},{"id":"52740","messageId":"11890776112309-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890776111670-git-send-email-madcoder@debian.org","subject":"[PATCH 5/7] Further strbuf re-engineering.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:09Z","receivedAt":"2007-09-06T11:20:09Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n builtin-apply.c       |   30 +++++++-----------------\n builtin-blame.c       |   35 +++++++++------------------\n builtin-commit-tree.c |   60 +++++++++++-------------------------------------\n diff.c                |   27 +++++++--------------\n 4 files changed, 44 insertions(+), 108 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 25b1447..d70c6cf 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -12,6 +12,7 @@\n #include \"blob.h\"\n #include \"delta.h\"\n #include \"builtin.h\"\n+#include \"strbuf.h\"\n \n /*\n  *  --check turns on checking that the working tree matches the\n@@ -181,34 +182,21 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c\n \n static void *read_patch_file(int fd, unsigned long *sizep)\n {\n-\tunsigned long size = 0, alloc = CHUNKSIZE;\n-\tvoid *buffer = xmalloc(alloc);\n+\tstruct strbuf buf;\n \n-\tfor (;;) {\n-\t\tssize_t nr = alloc - size;\n-\t\tif (nr < 1024) {\n-\t\t\talloc += CHUNKSIZE;\n-\t\t\tbuffer = xrealloc(buffer, alloc);\n-\t\t\tnr = alloc - size;\n-\t\t}\n-\t\tnr = xread(fd, (char *) buffer + size, nr);\n-\t\tif (!nr)\n-\t\t\tbreak;\n-\t\tif (nr < 0)\n-\t\t\tdie(\"git-apply: read returned %s\", strerror(errno));\n-\t\tsize += nr;\n-\t}\n-\t*sizep = size;\n+        strbuf_init(&buf);\n+\tif (strbuf_read(&buf, fd) < 0)\n+\t\tdie(\"git-apply: read returned %s\", strerror(errno));\n+\t*sizep = buf.len;\n \n \t/*\n \t * Make sure that we have some slop in the buffer\n \t * so that we can do speculative \"memcmp\" etc, and\n \t * see to it that it is NUL-filled.\n \t */\n-\tif (alloc < size + SLOP)\n-\t\tbuffer = xrealloc(buffer, size + SLOP);\n-\tmemset((char *) buffer + size, 0, SLOP);\n-\treturn buffer;\n+\tstrbuf_grow(&buf, SLOP);\n+\tmemset(buf.buf + buf.len, 0, SLOP);\n+\treturn strbuf_detach(&buf);\n }\n \n static unsigned long linelen(const char *buffer, unsigned long size)\ndiff --git a/builtin-blame.c b/builtin-blame.c\nindex dc88a95..1b1e6da 100644\n--- a/builtin-blame.c\n+++ b/builtin-blame.c\n@@ -18,6 +18,7 @@\n #include \"cache-tree.h\"\n #include \"path-list.h\"\n #include \"mailmap.h\"\n+#include \"strbuf.h\"\n \n static char blame_usage[] =\n \"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\\n\"\n@@ -2001,11 +2002,10 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \tstruct commit *commit;\n \tstruct origin *origin;\n \tunsigned char head_sha1[20];\n-\tchar *buf;\n+\tstruct strbuf buf;\n \tconst char *ident;\n \tint fd;\n \ttime_t now;\n-\tunsigned long fin_size;\n \tint size, len;\n \tstruct cache_entry *ce;\n \tunsigned mode;\n@@ -2023,9 +2023,11 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \n \torigin = make_origin(commit, path);\n \n+\tstrbuf_init(&buf);\n \tif (!contents_from || strcmp(\"-\", contents_from)) {\n \t\tstruct stat st;\n \t\tconst char *read_from;\n+\t\tunsigned long fin_size;\n \n \t\tif (contents_from) {\n \t\t\tif (stat(contents_from, &st) < 0)\n@@ -2038,19 +2040,19 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \t\t\tread_from = path;\n \t\t}\n \t\tfin_size = xsize_t(st.st_size);\n-\t\tbuf = xmalloc(fin_size+1);\n \t\tmode = canon_mode(st.st_mode);\n \t\tswitch (st.st_mode & S_IFMT) {\n \t\tcase S_IFREG:\n \t\t\tfd = open(read_from, O_RDONLY);\n \t\t\tif (fd < 0)\n \t\t\t\tdie(\"cannot open %s\", read_from);\n-\t\t\tif (read_in_full(fd, buf, fin_size) != fin_size)\n+\t\t\tif (strbuf_read(&buf, fd) != xsize_t(st.st_size))\n \t\t\t\tdie(\"cannot read %s\", read_from);\n \t\t\tbreak;\n \t\tcase S_IFLNK:\n-\t\t\tif (readlink(read_from, buf, fin_size+1) != fin_size)\n+\t\t\tif (readlink(read_from, buf.buf, buf.alloc) != fin_size)\n \t\t\t\tdie(\"cannot readlink %s\", read_from);\n+\t\t\tbuf.len = fin_size;\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tdie(\"unsupported file type %s\", read_from);\n@@ -2059,26 +2061,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con\n \telse {\n \t\t/* Reading from stdin */\n \t\tcontents_from = \"standard input\";\n-\t\tbuf = NULL;\n-\t\tfin_size = 0;\n \t\tmode = 0;\n-\t\twhile (1) {\n-\t\t\tssize_t cnt = 8192;\n-\t\t\tbuf = xrealloc(buf, fin_size + cnt);\n-\t\t\tcnt = xread(0, buf + fin_size, cnt);\n-\t\t\tif (cnt < 0)\n-\t\t\t\tdie(\"read error %s from stdin\",\n-\t\t\t\t    strerror(errno));\n-\t\t\tif (!cnt)\n-\t\t\t\tbreak;\n-\t\t\tfin_size += cnt;\n-\t\t}\n-\t\tbuf = xrealloc(buf, fin_size + 1);\n+\t\tif (strbuf_read(&buf, 0) < 0)\n+\t\t\tdie(\"read error %s from stdin\", strerror(errno));\n \t}\n-\tbuf[fin_size] = 0;\n-\torigin->file.ptr = buf;\n-\torigin->file.size = fin_size;\n-\tpretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);\n+\torigin->file.ptr = buf.buf;\n+\torigin->file.size = buf.len;\n+\tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);\n \tcommit->util = origin;\n \n \t/*\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex ccbcbe3..bc9502c 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -8,42 +8,13 @@\n #include \"tree.h\"\n #include \"builtin.h\"\n #include \"utf8.h\"\n+#include \"strbuf.h\"\n \n #define BLOCKING (1ul << 14)\n \n /*\n  * FIXME! Share the code with \"write-tree.c\"\n  */\n-static void init_buffer(char **bufp, unsigned int *sizep)\n-{\n-\t*bufp = xmalloc(BLOCKING);\n-\t*sizep = 0;\n-}\n-\n-static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)\n-{\n-\tchar one_line[2048];\n-\tva_list args;\n-\tint len;\n-\tunsigned long alloc, size, newsize;\n-\tchar *buf;\n-\n-\tva_start(args, fmt);\n-\tlen = vsnprintf(one_line, sizeof(one_line), fmt, args);\n-\tva_end(args);\n-\tsize = *sizep;\n-\tnewsize = size + len + 1;\n-\talloc = (size + 32767) & ~32767;\n-\tbuf = *bufp;\n-\tif (newsize > alloc) {\n-\t\talloc = (newsize + 32767) & ~32767;\n-\t\tbuf = xrealloc(buf, alloc);\n-\t\t*bufp = buf;\n-\t}\n-\t*sizep = newsize - 1;\n-\tmemcpy(buf + size, one_line, len);\n-}\n-\n static void check_valid(unsigned char *sha1, enum object_type expect)\n {\n \tenum object_type type = sha1_object_info(sha1, NULL);\n@@ -87,9 +58,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \tint parents = 0;\n \tunsigned char tree_sha1[20];\n \tunsigned char commit_sha1[20];\n-\tchar comment[1000];\n-\tchar *buffer;\n-\tunsigned int size;\n+\tstruct strbuf buffer;\n \tint encoding_is_utf8;\n \n \tgit_config(git_default_config);\n@@ -118,8 +87,9 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t/* Not having i18n.commitencoding is the same as having utf-8 */\n \tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n \n-\tinit_buffer(&buffer, &size);\n-\tadd_buffer(&buffer, &size, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\tstrbuf_init(&buffer);\n+\tstrbuf_grow(&buffer, 8192); /* should avoid reallocs for the headers */\n+\tstrbuf_addf(&buffer, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n \n \t/*\n \t * NOTE! This ordering means that the same exact tree merged with a\n@@ -127,26 +97,24 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t * if everything else stays the same.\n \t */\n \tfor (i = 0; i < parents; i++)\n-\t\tadd_buffer(&buffer, &size, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n+\t\tstrbuf_addf(&buffer, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n \n \t/* Person/date information */\n-\tadd_buffer(&buffer, &size, \"author %s\\n\", git_author_info(1));\n-\tadd_buffer(&buffer, &size, \"committer %s\\n\", git_committer_info(1));\n+\tstrbuf_addf(&buffer, \"author %s\\n\", git_author_info(1));\n+\tstrbuf_addf(&buffer, \"committer %s\\n\", git_committer_info(1));\n \tif (!encoding_is_utf8)\n-\t\tadd_buffer(&buffer, &size,\n-\t\t\t\t\"encoding %s\\n\", git_commit_encoding);\n-\tadd_buffer(&buffer, &size, \"\\n\");\n+\t\tstrbuf_addf(&buffer, \"encoding %s\\n\", git_commit_encoding);\n+\tstrbuf_addch(&buffer, '\\n');\n \n \t/* And add the comment */\n-\twhile (fgets(comment, sizeof(comment), stdin) != NULL)\n-\t\tadd_buffer(&buffer, &size, \"%s\", comment);\n+\tif (strbuf_read(&buffer, 0) < 0)\n+\t\tdie(\"git-commit-tree: read returned %s\", strerror(errno));\n \n \t/* And check the encoding */\n-\tbuffer[size] = '\\0';\n-\tif (encoding_is_utf8 && !is_utf8(buffer))\n+\tif (encoding_is_utf8 && !is_utf8(buffer.buf))\n \t\tfprintf(stderr, commit_utf8_warn);\n \n-\tif (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {\n+\tif (!write_sha1_file(buffer.buf, buffer.len, commit_type, commit_sha1)) {\n \t\tprintf(\"%s\\n\", sha1_to_hex(commit_sha1));\n \t\treturn 0;\n \t}\ndiff --git a/diff.c b/diff.c\nindex 0d30d05..c054b23 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -9,6 +9,7 @@\n #include \"xdiff-interface.h\"\n #include \"color.h\"\n #include \"attr.h\"\n+#include \"strbuf.h\"\n \n #ifdef NO_FAST_WORKING_DIRECTORY\n #define FAST_WORKING_DIRECTORY 0\n@@ -1545,26 +1546,16 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \n static int populate_from_stdin(struct diff_filespec *s)\n {\n-#define INCREMENT 1024\n-\tchar *buf;\n-\tunsigned long size;\n-\tssize_t got;\n-\n-\tsize = 0;\n-\tbuf = NULL;\n-\twhile (1) {\n-\t\tbuf = xrealloc(buf, size + INCREMENT);\n-\t\tgot = xread(0, buf + size, INCREMENT);\n-\t\tif (!got)\n-\t\t\tbreak; /* EOF */\n-\t\tif (got < 0)\n-\t\t\treturn error(\"error while reading from stdin %s\",\n+\tstruct strbuf buf;\n+\n+\tstrbuf_init(&buf);\n+\tif (strbuf_read(&buf, 0) < 0)\n+\t\treturn error(\"error while reading from stdin %s\",\n \t\t\t\t     strerror(errno));\n-\t\tsize += got;\n-\t}\n+\n \ts->should_munmap = 0;\n-\ts->data = buf;\n-\ts->size = size;\n+\ts->size = buf.len;\n+\ts->data = strbuf_detach(&buf);\n \ts->should_free = 1;\n \treturn 0;\n }\n-- \n1.5.3.1\n"},{"id":"52737","messageId":"11890776112641-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890776112309-git-send-email-madcoder@debian.org","subject":"[PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:10Z","receivedAt":"2007-09-06T11:20:10Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n builtin-rerere.c |   56 +++++++++++++++++------------------------------------\n 1 files changed, 18 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin-rerere.c b/builtin-rerere.c\nindex 29d057c..7ebf6f1 100644\n--- a/builtin-rerere.c\n+++ b/builtin-rerere.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"path-list.h\"\n+#include \"strbuf.h\"\n #include \"xdiff/xdiff.h\"\n #include \"xdiff-interface.h\"\n \n@@ -66,41 +67,20 @@ static int write_rr(struct path_list *rr, int out_fd)\n \treturn commit_lock_file(&write_lock);\n }\n \n-struct buffer {\n-\tchar *ptr;\n-\tint nr, alloc;\n-};\n-\n-static void append_line(struct buffer *buffer, const char *line)\n-{\n-\tint len = strlen(line);\n-\n-\tif (buffer->nr + len > buffer->alloc) {\n-\t\tbuffer->alloc = alloc_nr(buffer->nr + len);\n-\t\tbuffer->ptr = xrealloc(buffer->ptr, buffer->alloc);\n-\t}\n-\tmemcpy(buffer->ptr + buffer->nr, line, len);\n-\tbuffer->nr += len;\n-}\n-\n-static void clear_buffer(struct buffer *buffer)\n-{\n-\tfree(buffer->ptr);\n-\tbuffer->ptr = NULL;\n-\tbuffer->nr = buffer->alloc = 0;\n-}\n-\n static int handle_file(const char *path,\n \t unsigned char *sha1, const char *output)\n {\n \tSHA_CTX ctx;\n \tchar buf[1024];\n \tint hunk = 0, hunk_no = 0;\n-\tstruct buffer minus = { NULL, 0, 0 }, plus = { NULL, 0, 0 };\n-\tstruct buffer *one = &minus, *two = &plus;\n+\tstruct strbuf minus, plus;\n+\tstruct strbuf *one = &minus, *two = &plus;\n \tFILE *f = fopen(path, \"r\");\n \tFILE *out;\n \n+        strbuf_init(&minus);\n+        strbuf_init(&plus);\n+\n \tif (!f)\n \t\treturn error(\"Could not open %s\", path);\n \n@@ -122,36 +102,36 @@ static int handle_file(const char *path,\n \t\telse if (!prefixcmp(buf, \"=======\"))\n \t\t\thunk = 2;\n \t\telse if (!prefixcmp(buf, \">>>>>>> \")) {\n-\t\t\tint one_is_longer = (one->nr > two->nr);\n-\t\t\tint common_len = one_is_longer ? two->nr : one->nr;\n-\t\t\tint cmp = memcmp(one->ptr, two->ptr, common_len);\n+\t\t\tint one_is_longer = (one->len > two->len);\n+\t\t\tint common_len = one_is_longer ? two->len : one->len;\n+\t\t\tint cmp = memcmp(one->buf, two->buf, common_len);\n \n \t\t\thunk_no++;\n \t\t\thunk = 0;\n \t\t\tif ((cmp > 0) || ((cmp == 0) && one_is_longer)) {\n-\t\t\t\tstruct buffer *swap = one;\n+\t\t\t\tstruct strbuf *swap = one;\n \t\t\t\tone = two;\n \t\t\t\ttwo = swap;\n \t\t\t}\n \t\t\tif (out) {\n \t\t\t\tfputs(\"<<<<<<<\\n\", out);\n-\t\t\t\tfwrite(one->ptr, one->nr, 1, out);\n+\t\t\t\tfwrite(one->buf, one->len, 1, out);\n \t\t\t\tfputs(\"=======\\n\", out);\n-\t\t\t\tfwrite(two->ptr, two->nr, 1, out);\n+\t\t\t\tfwrite(two->buf, two->len, 1, out);\n \t\t\t\tfputs(\">>>>>>>\\n\", out);\n \t\t\t}\n \t\t\tif (sha1) {\n-\t\t\t\tSHA1_Update(&ctx, one->ptr, one->nr);\n+\t\t\t\tSHA1_Update(&ctx, one->buf, one->len);\n \t\t\t\tSHA1_Update(&ctx, \"\\0\", 1);\n-\t\t\t\tSHA1_Update(&ctx, two->ptr, two->nr);\n+\t\t\t\tSHA1_Update(&ctx, two->buf, two->len);\n \t\t\t\tSHA1_Update(&ctx, \"\\0\", 1);\n \t\t\t}\n-\t\t\tclear_buffer(one);\n-\t\t\tclear_buffer(two);\n+\t\t\tstrbuf_release(one);\n+\t\t\tstrbuf_release(two);\n \t\t} else if (hunk == 1)\n-\t\t\tappend_line(one, buf);\n+\t\t\tstrbuf_addstr(one, buf);\n \t\telse if (hunk == 2)\n-\t\t\tappend_line(two, buf);\n+\t\t\tstrbuf_addstr(two, buf);\n \t\telse if (out)\n \t\t\tfputs(buf, out);\n \t}\n-- \n1.5.3.1\n"},{"id":"52739","messageId":"11890776111167-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11890776112641-git-send-email-madcoder@debian.org","subject":"[PATCH 7/7] More strbuf uses in cache-tree.c.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T11:20:11Z","receivedAt":"2007-09-06T11:20:11Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Should even be marginally faster.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n cache-tree.c |   59 +++++++++++++++++++++------------------------------------\n 1 files changed, 22 insertions(+), 37 deletions(-)\n\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 077f034..76af6f5 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"strbuf.h\"\n #include \"tree.h\"\n #include \"cache-tree.h\"\n \n@@ -235,8 +236,7 @@ static int update_one(struct cache_tree *it,\n \t\t      int missing_ok,\n \t\t      int dryrun)\n {\n-\tunsigned long size, offset;\n-\tchar *buffer;\n+\tstruct strbuf buffer;\n \tint i;\n \n \tif (0 <= it->entry_count && has_sha1_file(it->sha1))\n@@ -293,9 +293,8 @@ static int update_one(struct cache_tree *it,\n \t/*\n \t * Then write out the tree object for this level.\n \t */\n-\tsize = 8192;\n-\tbuffer = xmalloc(size);\n-\toffset = 0;\n+\tstrbuf_init(&buffer);\n+\tstrbuf_grow(&buffer, 8192);\n \n \tfor (i = 0; i < entries; i++) {\n \t\tstruct cache_entry *ce = cache[i];\n@@ -332,15 +331,9 @@ static int update_one(struct cache_tree *it,\n \t\tif (!ce->ce_mode)\n \t\t\tcontinue; /* entry being removed */\n \n-\t\tif (size < offset + entlen + 100) {\n-\t\t\tsize = alloc_nr(offset + entlen + 100);\n-\t\t\tbuffer = xrealloc(buffer, size);\n-\t\t}\n-\t\toffset += sprintf(buffer + offset,\n-\t\t\t\t  \"%o %.*s\", mode, entlen, path + baselen);\n-\t\tbuffer[offset++] = 0;\n-\t\thashcpy((unsigned char*)buffer + offset, sha1);\n-\t\toffset += 20;\n+\t\tstrbuf_grow(&buffer, entlen + 100);\n+\t\tstrbuf_addf(&buffer, \"%o %.*s%c\", mode, entlen, path + baselen, '\\0');\n+\t\tstrbuf_add(&buffer, sha1, 20);\n \n #if DEBUG\n \t\tfprintf(stderr, \"cache-tree update-one %o %.*s\\n\",\n@@ -349,10 +342,10 @@ static int update_one(struct cache_tree *it,\n \t}\n \n \tif (dryrun)\n-\t\thash_sha1_file(buffer, offset, tree_type, it->sha1);\n+\t\thash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);\n \telse\n-\t\twrite_sha1_file(buffer, offset, tree_type, it->sha1);\n-\tfree(buffer);\n+\t\twrite_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);\n+\tstrbuf_release(&buffer);\n \tit->entry_count = i;\n #if DEBUG\n \tfprintf(stderr, \"cache-tree update-one (%d ent, %d subtree) %s\\n\",\n@@ -378,12 +371,10 @@ int cache_tree_update(struct cache_tree *it,\n \treturn 0;\n }\n \n-static void *write_one(struct cache_tree *it,\n+static void write_one(struct cache_tree *it,\n \t\t       char *path,\n \t\t       int pathlen,\n-\t\t       char *buffer,\n-\t\t       unsigned long *size,\n-\t\t       unsigned long *offset)\n+\t\t\t   struct strbuf *buffer)\n {\n \tint i;\n \n@@ -393,13 +384,9 @@ static void *write_one(struct cache_tree *it,\n \t * tree-sha1 (missing if invalid)\n \t * subtree_nr \"cache-tree\" entries for subtrees.\n \t */\n-\tif (*size < *offset + pathlen + 100) {\n-\t\t*size = alloc_nr(*offset + pathlen + 100);\n-\t\tbuffer = xrealloc(buffer, *size);\n-\t}\n-\t*offset += sprintf(buffer + *offset, \"%.*s%c%d %d\\n\",\n-\t\t\t   pathlen, path, 0,\n-\t\t\t   it->entry_count, it->subtree_nr);\n+\tstrbuf_grow(buffer, pathlen + 100);\n+\tstrbuf_add(buffer, path, pathlen);\n+\tstrbuf_addf(buffer, \"%c%d %d\\n\", 0, it->entry_count, it->subtree_nr);\n \n #if DEBUG\n \tif (0 <= it->entry_count)\n@@ -412,8 +399,7 @@ static void *write_one(struct cache_tree *it,\n #endif\n \n \tif (0 <= it->entry_count) {\n-\t\thashcpy((unsigned char*)buffer + *offset, it->sha1);\n-\t\t*offset += 20;\n+\t\tstrbuf_add(buffer, it->sha1, 20);\n \t}\n \tfor (i = 0; i < it->subtree_nr; i++) {\n \t\tstruct cache_tree_sub *down = it->down[i];\n@@ -423,21 +409,20 @@ static void *write_one(struct cache_tree *it,\n \t\t\t\t\t     prev->name, prev->namelen) <= 0)\n \t\t\t\tdie(\"fatal - unsorted cache subtree\");\n \t\t}\n-\t\tbuffer = write_one(down->cache_tree, down->name, down->namelen,\n-\t\t\t\t   buffer, size, offset);\n+\t\twrite_one(down->cache_tree, down->name, down->namelen, buffer);\n \t}\n-\treturn buffer;\n }\n \n void *cache_tree_write(struct cache_tree *root, unsigned long *size_p)\n {\n \tchar path[PATH_MAX];\n-\tunsigned long size = 8192;\n-\tchar *buffer = xmalloc(size);\n+\tstruct strbuf buffer;\n \n-\t*size_p = 0;\n \tpath[0] = 0;\n-\treturn write_one(root, path, 0, buffer, &size, size_p);\n+\tstrbuf_init(&buffer);\n+\twrite_one(root, path, 0, &buffer);\n+\t*size_p = buffer.len;\n+\treturn strbuf_detach(&buffer);\n }\n \n static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)\n-- \n1.5.3.1\n"},{"id":"52746","messageId":"20070906125811.GA32400@coredump.intra.peff.net","threadId":"9753","inReplyTo":"11890776114037-git-send-email-madcoder@debian.org","subject":"Re: strbuf new API, take 2 for inclusion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-09-06T12:58:11Z","receivedAt":"2007-09-06T12:58:11Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 06, 2007 at 01:20:04PM +0200, Pierre Habouzit wrote:\n\n>   I've also stripped as many STRBUF_INIT uses as possible, some people\n> didn't liked it. I've kept its use for \"static\" strbufs where it's way\n> more convenient that a function call.\n\nThe STRBUF_INIT initializer just sets everything to '0' or NULL. Static\nobjects already have this done automagically by the compiler, so there's\nno need to use STRBUF_INIT at all there.\n\n-Peff\n"},{"id":"52750","messageId":"Pine.LNX.4.64.0709061504521.28586@racer.site","threadId":"9753","inReplyTo":"11890776112641-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-06T14:05:36Z","receivedAt":"2007-09-06T14:05:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 6 Sep 2007, Pierre Habouzit wrote:\n\n> Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n> ---\n>  builtin-rerere.c |   56 +++++++++++++++++------------------------------------\n>  1 files changed, 18 insertions(+), 38 deletions(-)\n\nI like that one very much, but ...\n\n>  \tFILE *f = fopen(path, \"r\");\n>  \tFILE *out;\n>  \n> +        strbuf_init(&minus);\n> +        strbuf_init(&plus);\n> +\n\nYou used spaces instead of tabs here.\n\nCiao,\nDscho\n"},{"id":"52751","messageId":"Pine.LNX.4.64.0709061506330.28586@racer.site","threadId":"9753","inReplyTo":"118907761140-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-06T14:09:28Z","receivedAt":"2007-09-06T14:09:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nlet me thank you for this very nicely done patch series.  Except for 5/7, \nthey look pretty much obvious changes to me.  I'll review that in detail \nlater.\n\nOn Thu, 6 Sep 2007, Pierre Habouzit wrote:\n\n> +#define STRBUF_INIT  { 0, 0, 0, NULL }\n\nWould not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \nstandards-keen as other people, who I have no doubt will gladly answer \nthis one.)\n\nCiao,\nDscho\n"},{"id":"52753","messageId":"20070906142155.GB3002@coredump.intra.peff.net","threadId":"9753","inReplyTo":"Pine.LNX.4.64.0709061506330.28586@racer.site","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-09-06T14:21:55Z","receivedAt":"2007-09-06T14:21:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 06, 2007 at 03:09:28PM +0100, Johannes Schindelin wrote:\n\n> let me thank you for this very nicely done patch series.  Except for 5/7, \n> they look pretty much obvious changes to me.  I'll review that in detail \n> later.\n\nI second that; I am glad somebody is taking an interest in this area\n(though I haven't closely reviewed the patches yet).\n\n> > +#define STRBUF_INIT  { 0, 0, 0, NULL }\n> \n> Would not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \n> standards-keen as other people, who I have no doubt will gladly answer \n> this one.)\n\nYes, it would, according to the standard.\n\n-Peff\n"},{"id":"52755","messageId":"85bqcfdfc7.fsf@lola.goethe.zz","threadId":"9753","inReplyTo":"Pine.LNX.4.64.0709061506330.28586@racer.site","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-09-06T14:43:36Z","receivedAt":"2007-09-06T14:43:36Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> let me thank you for this very nicely done patch series.  Except for 5/7, \n> they look pretty much obvious changes to me.  I'll review that in detail \n> later.\n>\n> On Thu, 6 Sep 2007, Pierre Habouzit wrote:\n>\n>> +#define STRBUF_INIT  { 0, 0, 0, NULL }\n>\n> Would not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \n> standards-keen as other people, who I have no doubt will gladly answer \n> this one.)\n\nAFAIR, non-specified static memory areas are initialized to zero bits,\nand NULL resp (void *)0 is not guaranteed to be represented by zero\nbits.\n\n-- \nDavid Kastrup, Kriemhildstr. 15, 44793 Bochum\n"},{"id":"52756","messageId":"857in3dfad.fsf@lola.goethe.zz","threadId":"9753","inReplyTo":"20070906142155.GB3002@coredump.intra.peff.net","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-09-06T14:44:42Z","receivedAt":"2007-09-06T14:44:42Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Sep 06, 2007 at 03:09:28PM +0100, Johannes Schindelin wrote:\n>\n>> let me thank you for this very nicely done patch series.  Except for 5/7, \n>> they look pretty much obvious changes to me.  I'll review that in detail \n>> later.\n>\n> I second that; I am glad somebody is taking an interest in this area\n> (though I haven't closely reviewed the patches yet).\n>\n>> > +#define STRBUF_INIT  { 0, 0, 0, NULL }\n>> \n>> Would not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \n>> standards-keen as other people, who I have no doubt will gladly answer \n>> this one.)\n>\n> Yes, it would, according to the standard.\n\nHave a citation for that?\n\n-- \nDavid Kastrup, Kriemhildstr. 15, 44793 Bochum\n"},{"id":"52758","messageId":"20070906145035.GA3546@coredump.intra.peff.net","threadId":"9753","inReplyTo":"857in3dfad.fsf@lola.goethe.zz","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-09-06T14:50:35Z","receivedAt":"2007-09-06T14:50:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 06, 2007 at 04:44:42PM +0200, David Kastrup wrote:\n\n> >> Would not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \n> >> standards-keen as other people, who I have no doubt will gladly answer \n> >> this one.)\n> >\n> > Yes, it would, according to the standard.\n> \n> Have a citation for that?\n\nOf course.\n\nSee ISO 9899:1999, section 6.7.8.\n\nParagraph 10:\n\n  If an object that has automatic storage duration is not initialized\n  explicitly, its value is indeterminate. If an object that has static\n  storage duration is not initialized explicitly, then:\n\n  -- if it has pointer type, it is initialized to a null pointer;\n\n  -- if it has arithmetic type, it is initialized to (positive or\n  unsigned) zero;\n\n  -- if it is an aggregate, every member is initialized (recursively)\n  according to these rules;\n\n  -- if it is a union, the first named member is initialized (recursively)\n  according to these rules.\n\nParagraph 21:\n\n  If there are fewer initializers in a brace-enclosed list than there\n  are elements or members of an aggregate, or fewer characters in a\n  string literal used to initialize an array of known size than there\n  are elements in the array, the remainder of the aggregate shall be\n  initialized implicitly the same as objects that have static storage\n  duration.\n\n-Peff\n"},{"id":"52759","messageId":"20070906145244.GB3546@coredump.intra.peff.net","threadId":"9753","inReplyTo":"85bqcfdfc7.fsf@lola.goethe.zz","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-09-06T14:52:44Z","receivedAt":"2007-09-06T14:52:44Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 06, 2007 at 04:43:36PM +0200, David Kastrup wrote:\n\n> > Would not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \n> > standards-keen as other people, who I have no doubt will gladly answer \n> > this one.)\n> \n> AFAIR, non-specified static memory areas are initialized to zero bits,\n> and NULL resp (void *)0 is not guaranteed to be represented by zero\n> bits.\n\nYou are right that the NULL pointer is not necessarily represented as\nzero bits, but static pointers are explicitly initialized to the NULL\npointer (not all-bits-zero).\n\n-Peff\n"},{"id":"52761","messageId":"85tzq7bzoz.fsf@lola.goethe.zz","threadId":"9753","inReplyTo":"20070906145035.GA3546@coredump.intra.peff.net","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-09-06T15:06:52Z","receivedAt":"2007-09-06T15:06:52Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Sep 06, 2007 at 04:44:42PM +0200, David Kastrup wrote:\n>\n>> >> Would not \"struct strbuf sb = { 0 };\" have the same effect?  (I am not so \n>> >> standards-keen as other people, who I have no doubt will gladly answer \n>> >> this one.)\n>> >\n>> > Yes, it would, according to the standard.\n>> \n>> Have a citation for that?\n>\n> Of course.\n>\n> See ISO 9899:1999, section 6.7.8.\n>\n> Paragraph 10:\n>\n>   If an object that has automatic storage duration is not initialized\n>   explicitly, its value is indeterminate. If an object that has static\n>   storage duration is not initialized explicitly, then:\n>\n>   -- if it has pointer type, it is initialized to a null pointer;\n\nThat's actually a new one to me.  I don't think that it has been\nalways the case in ANSI C.\n\nThanks.\n\n-- \nDavid Kastrup, Kriemhildstr. 15, 44793 Bochum\n"},{"id":"52762","messageId":"20070906153613.GA4008@coredump.intra.peff.net","threadId":"9753","inReplyTo":"85tzq7bzoz.fsf@lola.goethe.zz","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-09-06T15:36:13Z","receivedAt":"2007-09-06T15:36:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 06, 2007 at 05:06:52PM +0200, David Kastrup wrote:\n\n> >   If an object that has automatic storage duration is not initialized\n> >   explicitly, its value is indeterminate. If an object that has static\n> >   storage duration is not initialized explicitly, then:\n> >\n> >   -- if it has pointer type, it is initialized to a null pointer;\n> \n> That's actually a new one to me.  I don't think that it has been\n> always the case in ANSI C.\n\nI don't have the C89 standard, so it's hard to be authoritative.\nHowever, according to TCOR1 to the C89 standard, the original text of\n6.5.7 contained:\n\n  If an object that has static storage duration is not initialized\n  explicitly, it is initialized implicitly as if every member that has\n  arithmetic type were assigned 0 and every member that has pointer type\n  were assigned a null pointer constant.\n\nand was changed to:\n\n  If an object that has static storage duration is not initialized\n  explicitly, then:\n\n    - if it has pointer type, it is initialized to a null pointer;\n\n    - if it has arithmetic type, it is initialized to zero;\n\n    - if it is an aggregate, every member is initialized (recursively)\n      according to these rules;\n\n    - if it is a union, the first named member is initialized\n      (recursively) according to these rules.\n\nBut for the case of pointer initializations, both have the same effect.\nSo I think it has always been the case. Pre-ANSI, who knows. :)\n\nYou can find TCOR1 here:\n\n  http://www.open-std.org/jtc1/sc22/wg14/www/docs/tc1.htm\n\nAnd now I must go get some real work done instead of snooping through\nstandards. :)\n\n-Peff\n"},{"id":"52763","messageId":"46E02092.9020805@eudaptics.com","threadId":"9753","inReplyTo":"85tzq7bzoz.fsf@lola.goethe.zz","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-09-06T15:45:22Z","receivedAt":"2007-09-06T15:45:22Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"David Kastrup schrieb:\n> Jeff King <peff@peff.net> writes:\n>> See ISO 9899:1999, section 6.7.8.\n>>\n>> Paragraph 10:\n>>\n>>   If an object that has automatic storage duration is not initialized\n>>   explicitly, its value is indeterminate. If an object that has static\n>>   storage duration is not initialized explicitly, then:\n>>\n>>   -- if it has pointer type, it is initialized to a null pointer;\n> \n> That's actually a new one to me.  I don't think that it has been\n> always the case in ANSI C.\n\nAFAIR, this has always been the case.\n\n-- Hannes\n"},{"id":"52764","messageId":"85hcm7bxjl.fsf@lola.goethe.zz","threadId":"9753","inReplyTo":"20070906153613.GA4008@coredump.intra.peff.net","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-09-06T15:53:18Z","receivedAt":"2007-09-06T15:53:18Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Sep 06, 2007 at 05:06:52PM +0200, David Kastrup wrote:\n>\n>> >   If an object that has automatic storage duration is not initialized\n>> >   explicitly, its value is indeterminate. If an object that has static\n>> >   storage duration is not initialized explicitly, then:\n>> >\n>> >   -- if it has pointer type, it is initialized to a null pointer;\n>> \n>> That's actually a new one to me.  I don't think that it has been\n>> always the case in ANSI C.\n>\n> I don't have the C89 standard, so it's hard to be authoritative.\n> However, according to TCOR1 to the C89 standard, the original text of\n> 6.5.7 contained:\n>\n>   If an object that has static storage duration is not initialized\n>   explicitly, it is initialized implicitly as if every member that has\n>   arithmetic type were assigned 0 and every member that has pointer type\n>   were assigned a null pointer constant.\n\nMaybe I am confusing this with the effects of calloc or memset(...,0).\n\n> But for the case of pointer initializations, both have the same\n> effect.  So I think it has always been the case. Pre-ANSI, who\n> knows. :)\n\nIn the original K&R C, a null pointer likely could have been assumed\nto have zero bits throughout.  The non-zero-bits NULL pointer concept\njust reeks of standard committees...  So maybe this never had been an\nissue, for different reasons.\n\n> And now I must go get some real work done instead of snooping\n> through standards. :)\n\nSorry for the diversion.\n\n-- \nDavid Kastrup, Kriemhildstr. 15, 44793 Bochum\n"},{"id":"52781","messageId":"20070906171502.GF8451@artemis.corp","threadId":"9753","inReplyTo":"20070906125811.GA32400@coredump.intra.peff.net","subject":"Re: strbuf new API, take 2 for inclusion","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T17:15:02Z","receivedAt":"2007-09-06T17:15:02Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 12:58:11PM +0000, Jeff King wrote:\n> On Thu, Sep 06, 2007 at 01:20:04PM +0200, Pierre Habouzit wrote:\n> \n> >   I've also stripped as many STRBUF_INIT uses as possible, some people\n> > didn't liked it. I've kept its use for \"static\" strbufs where it's way\n> > more convenient that a function call.\n> \n> The STRBUF_INIT initializer just sets everything to '0' or NULL. Static\n> objects already have this done automagically by the compiler, so there's\n> no need to use STRBUF_INIT at all there.\n\n  Yes, Junio already did that remark. The reason is that it's forward\ncompatible: if we ever change strbuf's intitial value for some reason,\nwe would just have to rebuild the code. As junio disliked it (and I'm\nnot sure I love it either) I've used it where using the _init() function\nwas impractical.\n\n\n  And yes { 0 } would have worked the same as per C standard. It's just\nthat I setup my compiler to flag missing C89 initializers (because it\noften detects real errors).\n\n  Here are the whys'\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52782","messageId":"20070906171621.GA5305@coredump.intra.peff.net","threadId":"9753","inReplyTo":"20070906171502.GF8451@artemis.corp","subject":"Re: strbuf new API, take 2 for inclusion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-09-06T17:16:21Z","receivedAt":"2007-09-06T17:16:21Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 06, 2007 at 07:15:02PM +0200, Pierre Habouzit wrote:\n\n>   Yes, Junio already did that remark. The reason is that it's forward\n> compatible: if we ever change strbuf's intitial value for some reason,\n> we would just have to rebuild the code. As junio disliked it (and I'm\n> not sure I love it either) I've used it where using the _init() function\n> was impractical.\n\nOK, I missed that discussion. Thanks for the explanation.\n\n-Peff\n"},{"id":"52783","messageId":"20070906171734.GG8451@artemis.corp","threadId":"9753","inReplyTo":"Pine.LNX.4.64.0709061504521.28586@racer.site","subject":"Re: [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T17:17:34Z","receivedAt":"2007-09-06T17:17:34Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 02:05:36PM +0000, Johannes Schindelin wrote:\n> Hi,\n> \n> On Thu, 6 Sep 2007, Pierre Habouzit wrote:\n> \n> > Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n> > ---\n> >  builtin-rerere.c |   56 +++++++++++++++++------------------------------------\n> >  1 files changed, 18 insertions(+), 38 deletions(-)\n> \n> I like that one very much, but ...\n> \n> >  \tFILE *f = fopen(path, \"r\");\n> >  \tFILE *out;\n> >  \n> > +        strbuf_init(&minus);\n> > +        strbuf_init(&plus);\n> > +\n> \n> You used spaces instead of tabs here.\n\n  crap, and I did that in the 5th patch as well. well, I'll maybe send\nprivately a \"fixed\" version of the patch to junio then, to avoid\nflooding the list with spacing issues.\n\n  And I'll also set my vim to use tabs when I'm hacking on git.\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52784","messageId":"20070906171913.GH8451@artemis.corp","threadId":"9753","inReplyTo":"20070906171621.GA5305@coredump.intra.peff.net","subject":"Re: strbuf new API, take 2 for inclusion","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T17:19:13Z","receivedAt":"2007-09-06T17:19:13Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 05:16:21PM +0000, Jeff King wrote:\n> On Thu, Sep 06, 2007 at 07:15:02PM +0200, Pierre Habouzit wrote:\n> \n> >   Yes, Junio already did that remark. The reason is that it's forward\n> > compatible: if we ever change strbuf's intitial value for some reason,\n> > we would just have to rebuild the code. As junio disliked it (and I'm\n> > not sure I love it either) I've used it where using the _init() function\n> > was impractical.\n> \n> OK, I missed that discussion. Thanks for the explanation.\n\n  That was on IRC, maybe that's the why :)\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52788","messageId":"1189100963.3423.9.camel@hinata.boston.redhat.com","threadId":"9753","inReplyTo":"118907761140-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 1/7] Rework strbuf API and semantics.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-09-06T17:49:23Z","receivedAt":"2007-09-06T17:49:23Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Thu, 2007-09-06 at 13:20 +0200, Pierre Habouzit wrote:\n> The gory details are explained in strbuf.h. The change of semantics this\n> patch enforces is that the embeded buffer has always a '\\0' character after\n> its last byte, to always make it a C-string. The offs-by-one changes are all\n> related to that very change.\n> \n>   A strbuf can be used to store byte arrays, or as an extended string\n> library. The `buf' member can be passed to any C legacy string function,\n> because strbuf operations always ensure there is a terminating \\0 at the end\n> of the buffer, not accounted in the `len' field of the structure.\n> \n>   A strbuf can be used to generate a string/buffer whose final size is not\n> really known, and then \"strbuf_detach\" can be used to get the built buffer,\n> and keep the wrapping \"strbuf\" structure usable for further work again.\n> \n>   Other interesting feature: strbuf_grow(sb, size) ensure that there is\n> enough allocated space in `sb' to put `size' new octets of data in the\n> buffer. It helps avoiding reallocating data for nothing when the problem the\n> strbuf helps to solve has a known typical size.\n\nThis looks good, should be very useful.\n\nKristian\n"},{"id":"52790","messageId":"1189101569.3423.17.camel@hinata.boston.redhat.com","threadId":"9753","inReplyTo":"11890776111843-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-09-06T17:59:29Z","receivedAt":"2007-09-06T17:59:29Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Thu, 2007-09-06 at 13:20 +0200, Pierre Habouzit wrote:\n> This is just cleaner way to deal with strbufs, using its API rather than\n> reinventing it in the module (e.g. strbuf_append_string is just the plain\n> strbuf_addstr function, and it was used to perform what strbuf_addch does\n> anyways).\n> ---\n>  archive-tar.c |   65 ++++++++++++++-------------------------------------------\n>  1 files changed, 16 insertions(+), 49 deletions(-)\n> \n> diff --git a/archive-tar.c b/archive-tar.c\n> index a0763c5..c84d7c0 100644\n> --- a/archive-tar.c\n> +++ b/archive-tar.c\n> @@ -78,19 +78,6 @@ static void write_trailer(void)\n>  \t}\n>  }\n>  \n> -static void strbuf_append_string(struct strbuf *sb, const char *s)\n> -{\n> -\tint slen = strlen(s);\n> -\tint total = sb->len + slen;\n> -\tif (total + 1 > sb->alloc) {\n> -\t\tsb->buf = xrealloc(sb->buf, total + 1);\n> -\t\tsb->alloc = total + 1;\n> -\t}\n> -\tmemcpy(sb->buf + sb->len, s, slen);\n> -\tsb->len = total;\n> -\tsb->buf[total] = '\\0';\n> -}\n> -\n>  /*\n>   * pax extended header records have the format \"%u %s=%s\\n\".  %u contains\n>   * the size of the whole string (including the %u), the first %s is the\n> @@ -100,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n>  static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,\n>                                       const char *value, unsigned int valuelen)\n>  {\n> -\tchar *p;\n> -\tint len, total, tmp;\n> +\tint len, tmp;\n>  \n>  \t/* \"%u %s=%s\\n\" */\n>  \tlen = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;\n>  \tfor (tmp = len; tmp > 9; tmp /= 10)\n>  \t\tlen++;\n>  \n> -\ttotal = sb->len + len;\n> -\tif (total > sb->alloc) {\n> -\t\tsb->buf = xrealloc(sb->buf, total);\n> -\t\tsb->alloc = total;\n> -\t}\n> -\n> -\tp = sb->buf;\n> -\tp += sprintf(p, \"%u %s=\", len, keyword);\n> -\tmemcpy(p, value, valuelen);\n> -\tp += valuelen;\n> -\t*p = '\\n';\n> -\tsb->len = total;\n> +\tstrbuf_grow(sb, len);\n> +\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n> +\tstrbuf_add(sb, value, valuelen);\n> +\tstrbuf_addch(sb, '\\n');\n>  }\n\nThis entire function can be collapsed to just:\n\n\tstrbuf_addf(sb, \"%u %s=%.*s\\n\", len, keyword, valuelen, value);\n\n>  \n>  static unsigned int ustar_header_chksum(const struct ustar_header *header)\n> @@ -153,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n>  \tstruct strbuf ext_header;\n>  \n>  \tmemset(&header, 0, sizeof(header));\n> -\text_header.buf = NULL;\n> -\text_header.len = ext_header.alloc = 0;\n> +\tstrbuf_init(&ext_header);\n\nJust use your STRBUF_INIT macro?\n\n>  \tif (!sha1) {\n>  \t\t*header.typeflag = TYPEFLAG_GLOBAL_HEADER;\n> @@ -225,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n>  \n>  \tif (ext_header.len > 0) {\n>  \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n> -\t\tfree(ext_header.buf);\n>  \t}\n\nRemove excess braces?\n\n> +\tstrbuf_release(&ext_header);\n>  \twrite_blocked(&header, sizeof(header));\n>  \tif (S_ISREG(mode) && buffer && size > 0)\n>  \t\twrite_blocked(buffer, size);\n> @@ -235,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,\n>  static void write_global_extended_header(const unsigned char *sha1)\n>  {\n>  \tstruct strbuf ext_header;\n> -\text_header.buf = NULL;\n> -\text_header.len = ext_header.alloc = 0;\n> +\n> +\tstrbuf_init(&ext_header);\n\nSTRBUF_INIT macro?\n\n>  \tstrbuf_append_ext_header(&ext_header, \"comment\", sha1_to_hex(sha1), 40);\n>  \twrite_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);\n> -\tfree(ext_header.buf);\n> +\tstrbuf_release(&ext_header);\n>  }\n>  \n>  static int git_tar_config(const char *var, const char *value)\n> @@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n>                             const char *base, int baselen,\n>                             const char *filename, unsigned mode, int stage)\n>  {\n> -\tstatic struct strbuf path;\n> +\tstatic struct strbuf path = STRBUF_INIT;\n>  \tint filenamelen = strlen(filename);\n>  \tvoid *buffer;\n>  \tenum object_type type;\n>  \tunsigned long size;\n>  \n> -\tif (!path.alloc) {\n> -\t\tpath.buf = xmalloc(PATH_MAX);\n> -\t\tpath.alloc = PATH_MAX;\n> -\t\tpath.len = path.eof = 0;\n> -\t}\n> -\tif (path.alloc < baselen + filenamelen + 1) {\n> -\t\tfree(path.buf);\n> -\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n> -\t\tpath.alloc = baselen + filenamelen + 1;\n> -\t}\n> -\tmemcpy(path.buf, base, baselen);\n> -\tmemcpy(path.buf + baselen, filename, filenamelen);\n> -\tpath.len = baselen + filenamelen;\n> -\tpath.buf[path.len] = '\\0';\n> +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n> +\tstrbuf_reset(&path);\n\nDoes strbuf_reset() do anything here?\n\n> +\tstrbuf_add(&path, base, baselen);\n> +\tstrbuf_add(&path, filename, filenamelen);\n>  \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n> -\t\tstrbuf_append_string(&path, \"/\");\n> +\t\tstrbuf_addch(&path, '/');\n>  \t\tbuffer = NULL;\n>  \t\tsize = 0;\n>  \t} else {\n"},{"id":"52791","messageId":"20070906180858.GJ8451@artemis.corp","threadId":"9753","inReplyTo":"1189101569.3423.17.camel@hinata.boston.redhat.com","subject":"Re: [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T18:08:58Z","receivedAt":"2007-09-06T18:08:58Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 05:59:29PM +0000, Kristian Høgsberg wrote:\n> On Thu, 2007-09-06 at 13:20 +0200, Pierre Habouzit wrote:\n> > +\tstrbuf_grow(sb, len);\n> > +\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n> > +\tstrbuf_add(sb, value, valuelen);\n> > +\tstrbuf_addch(sb, '\\n');\n> >  }\n> \n> This entire function can be collapsed to just:\n> \n> \tstrbuf_addf(sb, \"%u %s=%.*s\\n\", len, keyword, valuelen, value);\n\n  yes, but it's less efficient, because %.*s says that sprintf must copy\nat most valuelen bytes from value, but it still has to stop if it finds\na \\0 before. And the strbuf_grow has sense because the extend policy at\nsnprintf time is optimistic: we try to write, and if it didn't fit, we\ntry again. So there is a huge benefit if we have a clue of the final\nsize.\n\n  I would not change a thing.\n\n> > +\tstrbuf_init(&ext_header);\n> \n> Just use your STRBUF_INIT macro?\n\n  Many people dilike it, I'm not sure it's a good idea either, and the\nperformance hit should be negligible, if it's not, then we can still\nmake the _init() function an inline.\n\n> >  \tif (ext_header.len > 0) {\n> >  \t\twrite_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);\n> > -\t\tfree(ext_header.buf);\n> >  \t}\n> \n> Remove excess braces?\n\n  bah, I don't like to strip braces so I won't do that, else you end up\nwith stupidities like:\n\n  if (foo)\n    // bar();\n\n  do_some_very_important_stuff();\n\n  Call me paranoid but well, it saved me so many times ...\n\n> > -\tmemcpy(path.buf, base, baselen);\n> > -\tmemcpy(path.buf + baselen, filename, filenamelen);\n> > -\tpath.len = baselen + filenamelen;\n> > -\tpath.buf[path.len] = '\\0';\n> > +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n> > +\tstrbuf_reset(&path);\n> \n> Does strbuf_reset() do anything here?\n> \n> > +\tstrbuf_add(&path, base, baselen);\n\n  Yes _reset() sets length to 0. so the add here will write at the start\nof the buffer again. It definitely is important !\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52794","messageId":"1189102714.3423.22.camel@hinata.boston.redhat.com","threadId":"9753","inReplyTo":"20070906180858.GJ8451@artemis.corp","subject":"Re: [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-09-06T18:18:34Z","receivedAt":"2007-09-06T18:18:34Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Thu, 2007-09-06 at 20:08 +0200, Pierre Habouzit wrote:\n> On Thu, Sep 06, 2007 at 05:59:29PM +0000, Kristian Høgsberg wrote:\n> > On Thu, 2007-09-06 at 13:20 +0200, Pierre Habouzit wrote:\n> > > +\tstrbuf_grow(sb, len);\n> > > +\tstrbuf_addf(sb, \"%u %s=\", len, keyword);\n> > > +\tstrbuf_add(sb, value, valuelen);\n> > > +\tstrbuf_addch(sb, '\\n');\n> > >  }\n> > \n> > This entire function can be collapsed to just:\n> > \n> > \tstrbuf_addf(sb, \"%u %s=%.*s\\n\", len, keyword, valuelen, value);\n> \n>   yes, but it's less efficient, because %.*s says that sprintf must copy\n> at most valuelen bytes from value, but it still has to stop if it finds\n> a \\0 before. And the strbuf_grow has sense because the extend policy at\n> snprintf time is optimistic: we try to write, and if it didn't fit, we\n> try again. So there is a huge benefit if we have a clue of the final\n> size.\n\nYeah, my strbuf_addf() suggestion doesn't work, since the format seems\nto indicate the embedded NULs indeed is allowed (the %u is the length of\nthe value), so *.% could truncate data.\n\n> > > -\tmemcpy(path.buf, base, baselen);\n> > > -\tmemcpy(path.buf + baselen, filename, filenamelen);\n> > > -\tpath.len = baselen + filenamelen;\n> > > -\tpath.buf[path.len] = '\\0';\n> > > +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n> > > +\tstrbuf_reset(&path);\n> > \n> > Does strbuf_reset() do anything here?\n> > \n> > > +\tstrbuf_add(&path, base, baselen);\n> \n>   Yes _reset() sets length to 0. so the add here will write at the start\n> of the buffer again. It definitely is important !\n\nBut where was length set to non-zero?  path is initialized on entry to\nthe function, and strbuf_grow() just increases the allocation, not\nlength, right?\n\nKristian\n"},{"id":"52795","messageId":"20070906182746.GK8451@artemis.corp","threadId":"9753","inReplyTo":"1189102714.3423.22.camel@hinata.boston.redhat.com","subject":"Re: [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T18:27:46Z","receivedAt":"2007-09-06T18:27:46Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 06:18:34PM +0000, Kristian Høgsberg wrote:\n> On Thu, 2007-09-06 at 20:08 +0200, Pierre Habouzit wrote:\n> > On Thu, Sep 06, 2007 at 05:59:29PM +0000, Kristian Høgsberg wrote:\n> > > On Thu, 2007-09-06 at 13:20 +0200, Pierre Habouzit wrote:\n> > > > -\tmemcpy(path.buf, base, baselen);\n> > > > -\tmemcpy(path.buf + baselen, filename, filenamelen);\n> > > > -\tpath.len = baselen + filenamelen;\n> > > > -\tpath.buf[path.len] = '\\0';\n> > > > +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n> > > > +\tstrbuf_reset(&path);\n> > > \n> > > Does strbuf_reset() do anything here?\n> > > \n> > > > +\tstrbuf_add(&path, base, baselen);\n> > \n> >   Yes _reset() sets length to 0. so the add here will write at the start\n> > of the buffer again. It definitely is important !\n> \n> But where was length set to non-zero?  path is initialized on entry to\n> the function, and strbuf_grow() just increases the allocation, not\n> length, right?\n\n  The path is static, hence when you reenter the function you have the\nlast value in it. The fact that it's static may be questionable, but it\nwas like it before, I kept it, I've supposed it was for performance\nreasons.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52797","messageId":"85hcm7a6t4.fsf@lola.goethe.zz","threadId":"9753","inReplyTo":"20070906171734.GG8451@artemis.corp","subject":"Re: [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-09-06T20:16:07Z","receivedAt":"2007-09-06T20:16:07Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n> On Thu, Sep 06, 2007 at 02:05:36PM +0000, Johannes Schindelin wrote:\n\n>> You used spaces instead of tabs here.\n>\n>   crap, and I did that in the 5th patch as well. well, I'll maybe send\n> privately a \"fixed\" version of the patch to junio then, to avoid\n> flooding the list with spacing issues.\n>\n>   And I'll also set my vim to use tabs when I'm hacking on git.\n\nJust use Emacs and\nM-x c-set-style RET linux RET\n\n-- \nDavid Kastrup, Kriemhildstr. 15, 44793 Bochum\n"},{"id":"52801","messageId":"20070906205408.GA26924@artemis.corp","threadId":"9753","inReplyTo":"85hcm7a6t4.fsf@lola.goethe.zz","subject":"Re: [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-06T20:54:08Z","receivedAt":"2007-09-06T20:54:08Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Sep 06, 2007 at 08:16:07PM +0000, David Kastrup wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> > On Thu, Sep 06, 2007 at 02:05:36PM +0000, Johannes Schindelin wrote:\n> \n> >> You used spaces instead of tabs here.\n> >\n> >   crap, and I did that in the 5th patch as well. well, I'll maybe send\n> > privately a \"fixed\" version of the patch to junio then, to avoid\n> > flooding the list with spacing issues.\n> >\n> >   And I'll also set my vim to use tabs when I'm hacking on git.\n> \n> Just use Emacs and\n> M-x c-set-style RET linux RET\n\n  I'll give you a hunch:\n\napt-cache showsrc vim|grep Uplo\n…, Pierre Habouzit <madcoder@debian.org>, …\n\n  And it's not like vim doesn't has this either :)\n\n  Anyways, we're going a bit OT aren't we ?\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52811","messageId":"46E0852F.4090005@lsrfire.ath.cx","threadId":"9753","inReplyTo":"20070906182746.GK8451@artemis.corp","subject":"Re: [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-09-06T22:54:39Z","receivedAt":"2007-09-06T22:54:39Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Pierre Habouzit schrieb:\n> On Thu, Sep 06, 2007 at 06:18:34PM +0000, Kristian Høgsberg wrote:\n>> On Thu, 2007-09-06 at 20:08 +0200, Pierre Habouzit wrote:\n>>> On Thu, Sep 06, 2007 at 05:59:29PM +0000, Kristian Høgsberg wrote:\n>>>> On Thu, 2007-09-06 at 13:20 +0200, Pierre Habouzit wrote:\n>>>>> -\tmemcpy(path.buf, base, baselen);\n>>>>> -\tmemcpy(path.buf + baselen, filename, filenamelen);\n>>>>> -\tpath.len = baselen + filenamelen;\n>>>>> -\tpath.buf[path.len] = '\\0';\n>>>>> +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n>>>>> +\tstrbuf_reset(&path);\n>>>> Does strbuf_reset() do anything here?\n>>>>\n>>>>> +\tstrbuf_add(&path, base, baselen);\n>>>   Yes _reset() sets length to 0. so the add here will write at the start\n>>> of the buffer again. It definitely is important !\n>> But where was length set to non-zero?  path is initialized on entry to\n>> the function, and strbuf_grow() just increases the allocation, not\n>> length, right?\n> \n>   The path is static, hence when you reenter the function you have the\n> last value in it. The fact that it's static may be questionable, but it\n> was like it before, I kept it, I've supposed it was for performance\n> reasons.\n\nYou're right, I've made it static to get the number of mallocs from\nnumber-of-files-in-archive down to one.  It was a ~10% speedup in the\nwarm cache case, so I could not resist. :)\n\nRené\n"},{"id":"52872","messageId":"7v642m7vhr.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"20070906171734.GG8451@artemis.corp","subject":"Re: [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-07T08:03:28Z","receivedAt":"2007-09-07T08:03:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   crap, and I did that in the 5th patch as well. well, I'll maybe send\n> privately a \"fixed\" version of the patch to junio then, to avoid\n> flooding the list with spacing issues.\n\nHeh, no need.  I can fix them up locally here.\n\nFor me personally, your use of Mail-Followup-To: header is very\nmuch more irritating.  When I want to talk to you, I want my MUA\nto put YOUR name on To: header, not Johannes.  I consider it\nrude and selfish to use M-F-T to avoid getting duplicates from a\nmailing list you subscribe to.\n\nI have said this often enough in the past, and have been trying\nnot to say this unless necessary.  It is sad and happy at the\nsame time that I still occasionary need to bring this up.\n\nSad because I have to get irritated enough before I say this,\nand happy because it means I found another person who is worth\ncommunicating with and expect to communicate again with on the\nlist.\n\nPlease, don't.\n"},{"id":"52878","messageId":"20070907090216.GG21418@artemis.corp","threadId":"9753","inReplyTo":"7v642m7vhr.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-07T09:02:16Z","receivedAt":"2007-09-07T09:02:16Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Fri, Sep 07, 2007 at 08:03:28AM +0000, Junio C Hamano wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> >   crap, and I did that in the 5th patch as well. well, I'll maybe send\n> > privately a \"fixed\" version of the patch to junio then, to avoid\n> > flooding the list with spacing issues.\n> \n> Heh, no need.  I can fix them up locally here.\n\n  okay, perfect.\n\n> For me personally, your use of Mail-Followup-To: header is very\n> much more irritating.  When I want to talk to you, I want my MUA\n> to put YOUR name on To: header, not Johannes.  I consider it\n> rude and selfish to use M-F-T to avoid getting duplicates from a\n> mailing list you subscribe to.\n> \n> I have said this often enough in the past, and have been trying\n> not to say this unless necessary.  It is sad and happy at the\n> same time that I still occasionary need to bring this up.\n> \n> Sad because I have to get irritated enough before I say this,\n\n  I'm sorry, I'll remove it (for the next mail though, I'm too lazy to\nchange that right now). It's a policy on Debian lists to force M-F-T,\nand it's indeed not very practical on lists like the lkml or git. I\ncould have guessed that myself.\n\n> and happy because it means I found another person who is worth\n> communicating with and expect to communicate again with on the\n> list.\n\n  heh, thanks :)\n\n> Please, don't.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52993","messageId":"11892523992761-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"20070902224213.GB431@artemis.corp","subject":"Use strbufs in commit.c (pretty printing)","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T11:53:16Z","receivedAt":"2007-09-08T11:53:16Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Here is a 3 patch series to use strbufs for the pretty printing\nfunctions in commit.c.\n\n  * The first one adds a needed useful function to strbufs (rtrim).\n  * The second one changes the semantics of interpolate (as the third\n    will need that) and fixes the rest of the code accordingly.\n  * Do the change.\n\n  Testsuite passes after step 2 and 3.\n"},{"id":"52992","messageId":"1189252399433-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"11892523992761-git-send-email-madcoder@debian.org","subject":"[PATCH 1/3] Add strbuf_rtrim (to remove trailing spaces).","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T11:53:17Z","receivedAt":"2007-09-08T11:53:17Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n strbuf.c |    7 +++++++\n strbuf.h |    3 +++\n 2 files changed, 10 insertions(+), 0 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex acc7fc8..565c343 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -28,6 +28,13 @@ void strbuf_grow(struct strbuf *sb, size_t extra) {\n \tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n }\n \n+void strbuf_rtrim(struct strbuf *sb)\n+{\n+    while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))\n+        sb->len--;\n+    sb->buf[sb->len] = '\\0';\n+}\n+\n void strbuf_add(struct strbuf *sb, const void *data, size_t len) {\n \tstrbuf_grow(sb, len);\n \tmemcpy(sb->buf + sb->len, data, len);\ndiff --git a/strbuf.h b/strbuf.h\nindex b40dc99..9b708cc 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -68,6 +68,9 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) {\n \n extern void strbuf_grow(struct strbuf *, size_t);\n \n+/*----- content related -----*/\n+extern void strbuf_rtrim(struct strbuf *);\n+\n /*----- add data in your buffer -----*/\n static inline void strbuf_addch(struct strbuf *sb, int c) {\n \tstrbuf_grow(sb, 1);\n-- \n1.5.3.1\n"},{"id":"52991","messageId":"1189252399316-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"1189252399433-git-send-email-madcoder@debian.org","subject":"[PATCH 2/3] Change semantics of interpolate to work like snprintf.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T11:53:18Z","receivedAt":"2007-09-08T11:53:18Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Also fix many off-by-ones and a useless memset.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n commit.c      |    9 ++++-----\n interpolate.c |   20 ++++++++------------\n 2 files changed, 12 insertions(+), 17 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex dc5a064..30db9f4 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -922,15 +922,14 @@ static long format_commit_message(const struct commit *commit,\n \n \tdo {\n \t\tchar *buf = *buf_p;\n-\t\tunsigned long space = *space_p;\n+\t\tunsigned long len;\n \n-\t\tspace = interpolate(buf, space, user_format,\n+\t\tlen = interpolate(buf, *space_p, user_format,\n \t\t\t\t    table, ARRAY_SIZE(table));\n-\t\tif (!space)\n+\t\tif (len < *space_p)\n \t\t\tbreak;\n-\t\tbuf = xrealloc(buf, space);\n+\t\tALLOC_GROW(buf, len + 1, *space_p);\n \t\t*buf_p = buf;\n-\t\t*space_p = space;\n \t} while (1);\n \tinterp_clear_table(table, ARRAY_SIZE(table));\n \ndiff --git a/interpolate.c b/interpolate.c\nindex 0082677..ff4fb10 100644\n--- a/interpolate.c\n+++ b/interpolate.c\n@@ -44,9 +44,8 @@ void interp_clear_table(struct interp *table, int ninterps)\n  *        { \"%%\", \"%\"},\n  *    }\n  *\n- * Returns 0 on a successful substitution pass that fits in result,\n- * Returns a number of bytes needed to hold the full substituted\n- * string otherwise.\n+ * Returns the length of the substituted string (not including the final \\0).\n+ * Like with snprintf, if the result is >= reslen, then it overflowed.\n  */\n \n unsigned long interpolate(char *result, unsigned long reslen,\n@@ -61,8 +60,6 @@ unsigned long interpolate(char *result, unsigned long reslen,\n \tint i;\n \tchar c;\n \n-        memset(result, 0, reslen);\n-\n \twhile ((c = *src)) {\n \t\tif (c == '%') {\n \t\t\t/* Try to match an interpolation string. */\n@@ -78,9 +75,9 @@ unsigned long interpolate(char *result, unsigned long reslen,\n \t\t\t\tvalue = interps[i].value;\n \t\t\t\tvaluelen = strlen(value);\n \n-\t\t\t\tif (newlen + valuelen + 1 < reslen) {\n+\t\t\t\tif (newlen + valuelen < reslen) {\n \t\t\t\t\t/* Substitute. */\n-\t\t\t\t\tstrncpy(dest, value, valuelen);\n+\t\t\t\t\tmemcpy(dest, value, valuelen);\n \t\t\t\t\tdest += valuelen;\n \t\t\t\t}\n \t\t\t\tnewlen += valuelen;\n@@ -89,14 +86,13 @@ unsigned long interpolate(char *result, unsigned long reslen,\n \t\t\t}\n \t\t}\n \t\t/* Straight copy one non-interpolation character. */\n-\t\tif (newlen + 1 < reslen)\n+\t\tif (newlen < reslen)\n \t\t\t*dest++ = *src;\n \t\tsrc++;\n \t\tnewlen++;\n \t}\n \n-\tif (newlen + 1 < reslen)\n-\t\treturn 0;\n-\telse\n-\t\treturn newlen + 2;\n+\tif (reslen > 0)\n+\t\t*dest = '\\0';\n+\treturn newlen;\n }\n-- \n1.5.3.1\n"},{"id":"52990","messageId":"11892523992038-git-send-email-madcoder@debian.org","threadId":"9753","inReplyTo":"1189252399316-git-send-email-madcoder@debian.org","subject":"[PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T11:53:19Z","receivedAt":"2007-09-08T11:53:19Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  Also remove the \"len\" parameter, as:\n  (1) it was used as a max boundary, and every caller used ~0u\n  (2) we check for final NUL no matter what, so it doesn't help for speed.\n\n  As a result most of the pp_* function takes 3 arguments less, and we need\na lot less local variables, this makes the code way more readable, and\neasier to extend if needed.\n\n  This patch also fixes some spacing and cosmetic issues.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n builtin-branch.c      |   15 +--\n builtin-log.c         |   12 +-\n builtin-rev-list.c    |   13 +-\n builtin-show-branch.c |   13 +-\n commit.c              |  330 ++++++++++++++++++-------------------------------\n commit.h              |    6 +-\n log-tree.c            |   56 +++------\n 7 files changed, 171 insertions(+), 274 deletions(-)\n\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex 5f5c182..68cd5f9 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -268,23 +268,22 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t}\n \n \tif (verbose) {\n-\t\tchar *subject = NULL;\n-\t\tunsigned long subject_len = 0;\n+\t\tstruct strbuf subject;\n \t\tconst char *sub = \" **** invalid ref ****\";\n \n+\t\tstrbuf_init(&subject);\n+\n \t\tcommit = lookup_commit(item->sha1);\n \t\tif (commit && !parse_commit(commit)) {\n-\t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,\n-\t\t\t\t\t    &subject, &subject_len, 0,\n-\t\t\t\t\t    NULL, NULL, 0);\n-\t\t\tsub = subject;\n+\t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit,\n+\t\t\t\t\t    &subject, 0, NULL, NULL, 0);\n+\t\t\tsub = subject.buf;\n \t\t}\n \t\tprintf(\"%c %s%-*s%s %s %s\\n\", c, branch_get_color(color),\n \t\t       maxwidth, item->name,\n \t\t       branch_get_color(COLOR_BRANCH_RESET),\n \t\t       find_unique_abbrev(item->sha1, abbrev), sub);\n-\t\tif (subject)\n-\t\t\tfree(subject);\n+\t\tstrbuf_release(&subject);\n \t} else {\n \t\tprintf(\"%c %s%s%s\\n\", c, branch_get_color(color), item->name,\n \t\t       branch_get_color(COLOR_BRANCH_RESET));\ndiff --git a/builtin-log.c b/builtin-log.c\nindex fa81c25..21b35a1 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -763,13 +763,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)\n \t\t\tsign = '-';\n \n \t\tif (verbose) {\n-\t\t\tchar *buf = NULL;\n-\t\t\tunsigned long buflen = 0;\n-\t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,\n-\t\t\t                    &buf, &buflen, 0, NULL, NULL, 0);\n+\t\t\tstruct strbuf buf;\n+\t\t\tstrbuf_init(&buf);\n+\t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit,\n+\t\t\t                    &buf, 0, NULL, NULL, 0);\n \t\t\tprintf(\"%c %s %s\\n\", sign,\n-\t\t\t       sha1_to_hex(commit->object.sha1), buf);\n-\t\t\tfree(buf);\n+\t\t\t       sha1_to_hex(commit->object.sha1), buf.buf);\n+\t\t\tstrbuf_release(&buf);\n \t\t}\n \t\telse {\n \t\t\tprintf(\"%c %s\\n\", sign,\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex ac551d5..7967f86 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -80,13 +80,12 @@ static void show_commit(struct commit *commit)\n \t\tputchar('\\n');\n \n \tif (revs.verbose_header) {\n-\t\tchar *buf = NULL;\n-\t\tunsigned long buflen = 0;\n-\t\tpretty_print_commit(revs.commit_format, commit, ~0,\n-\t\t\t\t    &buf, &buflen,\n-\t\t\t\t    revs.abbrev, NULL, NULL, revs.date_mode);\n-\t\tprintf(\"%s%c\", buf, hdr_termination);\n-\t\tfree(buf);\n+\t\tstruct strbuf buf;\n+\t\tstrbuf_init(&buf);\n+\t\tpretty_print_commit(revs.commit_format, commit,\n+\t\t\t\t\t&buf, revs.abbrev, NULL, NULL, revs.date_mode);\n+\t\tprintf(\"%s%c\", buf.buf, hdr_termination);\n+\t\tstrbuf_release(&buf);\n \t}\n \tmaybe_flush_or_die(stdout, \"stdout\");\n \tif (commit->parents) {\ndiff --git a/builtin-show-branch.c b/builtin-show-branch.c\nindex 4fa87f6..020116f 100644\n--- a/builtin-show-branch.c\n+++ b/builtin-show-branch.c\n@@ -259,16 +259,15 @@ static void join_revs(struct commit_list **list_p,\n \n static void show_one_commit(struct commit *commit, int no_name)\n {\n-\tchar *pretty = NULL;\n+\tstruct strbuf pretty;\n \tconst char *pretty_str = \"(unavailable)\";\n-\tunsigned long pretty_len = 0;\n \tstruct commit_name *name = commit->util;\n \n+\tstrbuf_init(&pretty);\n \tif (commit->object.parsed) {\n-\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,\n-\t\t\t\t    &pretty, &pretty_len,\n-\t\t\t\t    0, NULL, NULL, 0);\n-\t\tpretty_str = pretty;\n+\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit,\n+\t\t\t\t\t&pretty, 0, NULL, NULL, 0);\n+\t\tpretty_str = pretty.buf;\n \t}\n \tif (!prefixcmp(pretty_str, \"[PATCH] \"))\n \t\tpretty_str += 8;\n@@ -289,7 +288,7 @@ static void show_one_commit(struct commit *commit, int no_name)\n \t\t\t       find_unique_abbrev(commit->object.sha1, 7));\n \t}\n \tputs(pretty_str);\n-\tfree(pretty);\n+\tstrbuf_release(&pretty);\n }\n \n static char *ref_name[MAX_REVS + 1];\ndiff --git a/commit.c b/commit.c\nindex 30db9f4..dafa821 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -458,11 +458,11 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)\n /*\n  * Generic support for pretty-printing the header\n  */\n-static int get_one_line(const char *msg, unsigned long len)\n+static int get_one_line(const char *msg)\n {\n \tint ret = 0;\n \n-\twhile (len--) {\n+\tfor (;;) {\n \t\tchar c = *msg++;\n \t\tif (!c)\n \t\t\tbreak;\n@@ -485,31 +485,24 @@ static int is_rfc2047_special(char ch)\n \treturn (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));\n }\n \n-static int add_rfc2047(char *buf, const char *line, int len,\n+static void add_rfc2047(struct strbuf *sb, const char *line, int len,\n \t\t       const char *encoding)\n {\n-\tchar *bp = buf;\n-\tint i, needquote;\n-\tchar q_encoding[128];\n-\tconst char *q_encoding_fmt = \"=?%s?q?\";\n+\tint i, last;\n \n-\tfor (i = needquote = 0; !needquote && i < len; i++) {\n+\tfor (i = 0; i < len; i++) {\n \t\tint ch = line[i];\n \t\tif (non_ascii(ch))\n-\t\t\tneedquote++;\n-\t\tif ((i + 1 < len) &&\n-\t\t    (ch == '=' && line[i+1] == '?'))\n-\t\t\tneedquote++;\n+\t\t\tgoto needquote;\n+\t\tif ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))\n+\t\t\tgoto needquote;\n \t}\n-\tif (!needquote)\n-\t\treturn sprintf(buf, \"%.*s\", len, line);\n-\n-\ti = snprintf(q_encoding, sizeof(q_encoding), q_encoding_fmt, encoding);\n-\tif (sizeof(q_encoding) < i)\n-\t\tdie(\"Insanely long encoding name %s\", encoding);\n-\tmemcpy(bp, q_encoding, i);\n-\tbp += i;\n-\tfor (i = 0; i < len; i++) {\n+\tstrbuf_add(sb, line, len);\n+\treturn;\n+\n+needquote:\n+\tstrbuf_addf(sb, \"=?%s?q?\", encoding);\n+\tfor (i = last = 0; i < len; i++) {\n \t\tunsigned ch = line[i] & 0xFF;\n \t\t/*\n \t\t * We encode ' ' using '=20' even though rfc2047\n@@ -518,15 +511,13 @@ static int add_rfc2047(char *buf, const char *line, int len,\n \t\t * leave the underscore in place.\n \t\t */\n \t\tif (is_rfc2047_special(ch) || ch == ' ') {\n-\t\t\tsprintf(bp, \"=%02X\", ch);\n-\t\t\tbp += 3;\n+\t\t\tstrbuf_add(sb, line + last, i - last);\n+\t\t\tstrbuf_addf(sb, \"=%02X\", ch);\n+\t\t\tlast = i + 1;\n \t\t}\n-\t\telse\n-\t\t\t*bp++ = ch;\n \t}\n-\tmemcpy(bp, \"?=\", 2);\n-\tbp += 2;\n-\treturn bp - buf;\n+\tstrbuf_add(sb, line + last, len - last);\n+\tstrbuf_addstr(sb, \"?=\");\n }\n \n static unsigned long bound_rfc2047(unsigned long len, const char *encoding)\n@@ -537,21 +528,21 @@ static unsigned long bound_rfc2047(unsigned long len, const char *encoding)\n \treturn len * 3 + elen + 100;\n }\n \n-static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,\n+static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,\n \t\t\t const char *line, enum date_mode dmode,\n \t\t\t const char *encoding)\n {\n \tchar *date;\n \tint namelen;\n \tunsigned long time;\n-\tint tz, ret;\n+\tint tz;\n \tconst char *filler = \"    \";\n \n \tif (fmt == CMIT_FMT_ONELINE)\n-\t\treturn 0;\n+\t\treturn;\n \tdate = strchr(line, '>');\n \tif (!date)\n-\t\treturn 0;\n+\t\treturn;\n \tnamelen = ++date - line;\n \ttime = strtoul(date, &date, 10);\n \ttz = strtol(date, NULL, 10);\n@@ -560,42 +551,35 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,\n \t\tchar *name_tail = strchr(line, '<');\n \t\tint display_name_length;\n \t\tif (!name_tail)\n-\t\t\treturn 0;\n+\t\t\treturn;\n \t\twhile (line < name_tail && isspace(name_tail[-1]))\n \t\t\tname_tail--;\n \t\tdisplay_name_length = name_tail - line;\n \t\tfiller = \"\";\n-\t\tstrcpy(buf, \"From: \");\n-\t\tret = strlen(buf);\n-\t\tret += add_rfc2047(buf + ret, line, display_name_length,\n-\t\t\t\t   encoding);\n-\t\tmemcpy(buf + ret, name_tail, namelen - display_name_length);\n-\t\tret += namelen - display_name_length;\n-\t\tbuf[ret++] = '\\n';\n+\t\tstrbuf_addstr(sb, \"From: \");\n+\t\tadd_rfc2047(sb, line, display_name_length, encoding);\n+\t\tstrbuf_add(sb, name_tail, namelen - display_name_length);\n+\t\tstrbuf_addch(sb, '\\n');\n \t}\n \telse {\n-\t\tret = sprintf(buf, \"%s: %.*s%.*s\\n\", what,\n+\t\tstrbuf_addf(sb, \"%s: %.*s%.*s\\n\", what,\n \t\t\t      (fmt == CMIT_FMT_FULLER) ? 4 : 0,\n \t\t\t      filler, namelen, line);\n \t}\n \tswitch (fmt) {\n \tcase CMIT_FMT_MEDIUM:\n-\t\tret += sprintf(buf + ret, \"Date:   %s\\n\",\n-\t\t\t       show_date(time, tz, dmode));\n+\t\tstrbuf_addf(sb, \"Date:   %s\\n\", show_date(time, tz, dmode));\n \t\tbreak;\n \tcase CMIT_FMT_EMAIL:\n-\t\tret += sprintf(buf + ret, \"Date: %s\\n\",\n-\t\t\t       show_date(time, tz, DATE_RFC2822));\n+\t\tstrbuf_addf(sb, \"Date: %s\\n\", show_date(time, tz, DATE_RFC2822));\n \t\tbreak;\n \tcase CMIT_FMT_FULLER:\n-\t\tret += sprintf(buf + ret, \"%sDate: %s\\n\", what,\n-\t\t\t       show_date(time, tz, dmode));\n+\t\tstrbuf_addf(sb, \"%sDate: %s\\n\", what, show_date(time, tz, dmode));\n \t\tbreak;\n \tdefault:\n \t\t/* notin' */\n \t\tbreak;\n \t}\n-\treturn ret;\n }\n \n static int is_empty_line(const char *line, int *len_p)\n@@ -607,16 +591,16 @@ static int is_empty_line(const char *line, int *len_p)\n \treturn !len;\n }\n \n-static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *commit, int abbrev)\n+static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,\n+\t\t\tconst struct commit *commit, int abbrev)\n {\n \tstruct commit_list *parent = commit->parents;\n-\tint offset;\n \n \tif ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||\n \t    !parent || !parent->next)\n-\t\treturn 0;\n+\t\treturn;\n \n-\toffset = sprintf(buf, \"Merge:\");\n+\tstrbuf_addstr(sb, \"Merge:\");\n \n \twhile (parent) {\n \t\tstruct commit *p = parent->item;\n@@ -629,10 +613,9 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com\n \t\tdots = (abbrev && strlen(hex) != 40) ?  \"...\" : \"\";\n \t\tparent = parent->next;\n \n-\t\toffset += sprintf(buf + offset, \" %s%s\", hex, dots);\n+\t\tstrbuf_addf(sb, \" %s%s\", hex, dots);\n \t}\n-\tbuf[offset++] = '\\n';\n-\treturn offset;\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static char *get_header(const struct commit *commit, const char *key)\n@@ -787,8 +770,8 @@ static void fill_person(struct interp *table, const char *msg, int len)\n \tinterp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));\n }\n \n-static long format_commit_message(const struct commit *commit,\n-\t\tconst char *msg, char **buf_p, unsigned long *space_p)\n+static void format_commit_message(const struct commit *commit,\n+\t\tconst char *msg, struct strbuf *sb)\n {\n \tstruct interp table[] = {\n \t\t{ \"%H\" },\t/* commit hash */\n@@ -841,6 +824,7 @@ static long format_commit_message(const struct commit *commit,\n \t};\n \tstruct commit_list *p;\n \tchar parents[1024];\n+\tunsigned long len;\n \tint i;\n \tenum { HEADER, SUBJECT, BODY } state;\n \n@@ -920,20 +904,15 @@ static long format_commit_message(const struct commit *commit,\n \t\tif (!table[i].value)\n \t\t\tinterp_set_entry(table, i, \"<unknown>\");\n \n-\tdo {\n-\t\tchar *buf = *buf_p;\n-\t\tunsigned long len;\n-\n-\t\tlen = interpolate(buf, *space_p, user_format,\n-\t\t\t\t    table, ARRAY_SIZE(table));\n-\t\tif (len < *space_p)\n-\t\t\tbreak;\n-\t\tALLOC_GROW(buf, len + 1, *space_p);\n-\t\t*buf_p = buf;\n-\t} while (1);\n+\tlen = interpolate(sb->buf + sb->len, strbuf_avail(sb),\n+\t\t\t\tuser_format, table, ARRAY_SIZE(table));\n+\tif (len > strbuf_avail(sb)) {\n+\t\tstrbuf_grow(sb, len);\n+\t\tinterpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,\n+\t\t\t\t\tuser_format, table, ARRAY_SIZE(table));\n+\t}\n+\tstrbuf_setlen(sb, sb->len + len);\n \tinterp_clear_table(table, ARRAY_SIZE(table));\n-\n-\treturn strlen(*buf_p);\n }\n \n static void pp_header(enum cmit_fmt fmt,\n@@ -942,34 +921,24 @@ static void pp_header(enum cmit_fmt fmt,\n \t\t      const char *encoding,\n \t\t      const struct commit *commit,\n \t\t      const char **msg_p,\n-\t\t      unsigned long *len_p,\n-\t\t      unsigned long *ofs_p,\n-\t\t      char **buf_p,\n-\t\t      unsigned long *space_p)\n+\t\t      struct strbuf *sb)\n {\n \tint parents_shown = 0;\n \n \tfor (;;) {\n \t\tconst char *line = *msg_p;\n-\t\tchar *dst;\n-\t\tint linelen = get_one_line(*msg_p, *len_p);\n-\t\tunsigned long len;\n+\t\tint linelen = get_one_line(*msg_p);\n \n \t\tif (!linelen)\n \t\t\treturn;\n \t\t*msg_p += linelen;\n-\t\t*len_p -= linelen;\n \n \t\tif (linelen == 1)\n \t\t\t/* End of header */\n \t\t\treturn;\n \n-\t\tALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p);\n-\t\tdst = *buf_p + *ofs_p;\n-\n \t\tif (fmt == CMIT_FMT_RAW) {\n-\t\t\tmemcpy(dst, line, linelen);\n-\t\t\t*ofs_p += linelen;\n+\t\t\tstrbuf_add(sb, line, linelen);\n \t\t\tcontinue;\n \t\t}\n \n@@ -987,10 +956,8 @@ static void pp_header(enum cmit_fmt fmt,\n \t\t\t     parent = parent->next, num++)\n \t\t\t\t;\n \t\t\t/* with enough slop */\n-\t\t\tnum = *ofs_p + num * 50 + 20;\n-\t\t\tALLOC_GROW(*buf_p, num, *space_p);\n-\t\t\tdst = *buf_p + *ofs_p;\n-\t\t\t*ofs_p += add_merge_info(fmt, dst, commit, abbrev);\n+\t\t\tstrbuf_grow(sb, num * 50 + 20);\n+\t\t\tadd_merge_info(fmt, sb, commit, abbrev);\n \t\t\tparents_shown = 1;\n \t\t}\n \n@@ -1000,129 +967,100 @@ static void pp_header(enum cmit_fmt fmt,\n \t\t * FULLER shows both authors and dates.\n \t\t */\n \t\tif (!memcmp(line, \"author \", 7)) {\n-\t\t\tlen = linelen;\n+\t\t\tunsigned long len = linelen;\n \t\t\tif (fmt == CMIT_FMT_EMAIL)\n \t\t\t\tlen = bound_rfc2047(linelen, encoding);\n-\t\t\tALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);\n-\t\t\tdst = *buf_p + *ofs_p;\n-\t\t\t*ofs_p += add_user_info(\"Author\", fmt, dst,\n-\t\t\t\t\t\tline + 7, dmode, encoding);\n+\t\t\tstrbuf_grow(sb, len + 80);\n+\t\t\tadd_user_info(\"Author\", fmt, sb, line + 7, dmode, encoding);\n \t\t}\n \n \t\tif (!memcmp(line, \"committer \", 10) &&\n \t\t    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {\n-\t\t\tlen = linelen;\n+\t\t\tunsigned long len = linelen;\n \t\t\tif (fmt == CMIT_FMT_EMAIL)\n \t\t\t\tlen = bound_rfc2047(linelen, encoding);\n-\t\t\tALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);\n-\t\t\tdst = *buf_p + *ofs_p;\n-\t\t\t*ofs_p += add_user_info(\"Commit\", fmt, dst,\n-\t\t\t\t\t\tline + 10, dmode, encoding);\n+\t\t\tstrbuf_grow(sb, len + 80);\n+\t\t\tadd_user_info(\"Commit\", fmt, sb, line + 10, dmode, encoding);\n \t\t}\n \t}\n }\n \n static void pp_title_line(enum cmit_fmt fmt,\n \t\t\t  const char **msg_p,\n-\t\t\t  unsigned long *len_p,\n-\t\t\t  unsigned long *ofs_p,\n-\t\t\t  char **buf_p,\n-\t\t\t  unsigned long *space_p,\n-\t\t\t  int indent,\n+\t\t\t  struct strbuf *sb,\n \t\t\t  const char *subject,\n \t\t\t  const char *after_subject,\n \t\t\t  const char *encoding,\n \t\t\t  int plain_non_ascii)\n {\n-\tchar *title;\n-\tunsigned long title_alloc, title_len;\n+\tstruct strbuf title;\n \tunsigned long len;\n \n-\ttitle_len = 0;\n-\ttitle_alloc = 80;\n-\ttitle = xmalloc(title_alloc);\n+\tstrbuf_init(&title);\n+\tstrbuf_grow(&title, 80);\n+\n \tfor (;;) {\n \t\tconst char *line = *msg_p;\n-\t\tint linelen = get_one_line(line, *len_p);\n-\t\t*msg_p += linelen;\n-\t\t*len_p -= linelen;\n+\t\tint linelen = get_one_line(line);\n \n+\t\t*msg_p += linelen;\n \t\tif (!linelen || is_empty_line(line, &linelen))\n \t\t\tbreak;\n \n-\t\tif (title_alloc <= title_len + linelen + 2) {\n-\t\t\ttitle_alloc = title_len + linelen + 80;\n-\t\t\ttitle = xrealloc(title, title_alloc);\n-\t\t}\n-\t\tlen = 0;\n-\t\tif (title_len) {\n+\t\tstrbuf_grow(&title, linelen + 2);\n+\t\tif (title.len) {\n \t\t\tif (fmt == CMIT_FMT_EMAIL) {\n-\t\t\t\tlen++;\n-\t\t\t\ttitle[title_len++] = '\\n';\n+\t\t\t\tstrbuf_addch(&title, '\\n');\n \t\t\t}\n-\t\t\tlen++;\n-\t\t\ttitle[title_len++] = ' ';\n+\t\t\tstrbuf_addch(&title, ' ');\n \t\t}\n-\t\tmemcpy(title + title_len, line, linelen);\n-\t\ttitle_len += linelen;\n+\t\tstrbuf_add(&title, line, linelen);\n \t}\n \n \t/* Enough slop for the MIME header and rfc2047 */\n-\tlen = bound_rfc2047(title_len, encoding)+ 1000;\n+\tlen = bound_rfc2047(title.len, encoding) + 1000;\n \tif (subject)\n \t\tlen += strlen(subject);\n \tif (after_subject)\n \t\tlen += strlen(after_subject);\n \tif (encoding)\n \t\tlen += strlen(encoding);\n-\tALLOC_GROW(*buf_p, title_len + *ofs_p + len, *space_p);\n \n+\tstrbuf_grow(sb, title.len + len);\n \tif (subject) {\n-\t\tlen = strlen(subject);\n-\t\tmemcpy(*buf_p + *ofs_p, subject, len);\n-\t\t*ofs_p += len;\n-\t\t*ofs_p += add_rfc2047(*buf_p + *ofs_p,\n-\t\t\t\t      title, title_len, encoding);\n+\t\tstrbuf_addstr(sb, subject);\n+\t\tadd_rfc2047(sb, title.buf, title.len, encoding);\n \t} else {\n-\t\tmemcpy(*buf_p + *ofs_p, title, title_len);\n-\t\t*ofs_p += title_len;\n+\t\tstrbuf_addbuf(sb, &title);\n \t}\n-\t(*buf_p)[(*ofs_p)++] = '\\n';\n+\tstrbuf_addch(sb, '\\n');\n+\n \tif (plain_non_ascii) {\n \t\tconst char *header_fmt =\n \t\t\t\"MIME-Version: 1.0\\n\"\n \t\t\t\"Content-Type: text/plain; charset=%s\\n\"\n \t\t\t\"Content-Transfer-Encoding: 8bit\\n\";\n-\t\t*ofs_p += snprintf(*buf_p + *ofs_p,\n-\t\t\t\t   *space_p - *ofs_p,\n-\t\t\t\t   header_fmt, encoding);\n+\t\tstrbuf_addf(sb, header_fmt, encoding);\n \t}\n \tif (after_subject) {\n-\t\tlen = strlen(after_subject);\n-\t\tmemcpy(*buf_p + *ofs_p, after_subject, len);\n-\t\t*ofs_p += len;\n+\t\tstrbuf_addstr(sb, after_subject);\n \t}\n-\tfree(title);\n \tif (fmt == CMIT_FMT_EMAIL) {\n-\t\tALLOC_GROW(*buf_p, *ofs_p + 20, *space_p);\n-\t\t(*buf_p)[(*ofs_p)++] = '\\n';\n+\t\tstrbuf_addch(sb, '\\n');\n \t}\n+\tstrbuf_release(&title);\n }\n \n static void pp_remainder(enum cmit_fmt fmt,\n \t\t\t const char **msg_p,\n-\t\t\t unsigned long *len_p,\n-\t\t\t unsigned long *ofs_p,\n-\t\t\t char **buf_p,\n-\t\t\t unsigned long *space_p,\n+\t\t\t struct strbuf *sb,\n \t\t\t int indent)\n {\n \tint first = 1;\n \tfor (;;) {\n \t\tconst char *line = *msg_p;\n-\t\tint linelen = get_one_line(line, *len_p);\n+\t\tint linelen = get_one_line(line);\n \t\t*msg_p += linelen;\n-\t\t*len_p -= linelen;\n \n \t\tif (!linelen)\n \t\t\tbreak;\n@@ -1135,36 +1073,30 @@ static void pp_remainder(enum cmit_fmt fmt,\n \t\t}\n \t\tfirst = 0;\n \n-\t\tALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p);\n+\t\tstrbuf_grow(sb, linelen + indent + 20);\n \t\tif (indent) {\n-\t\t\tmemset(*buf_p + *ofs_p, ' ', indent);\n-\t\t\t*ofs_p += indent;\n+\t\t\tmemset(sb->buf + sb->len, ' ', indent);\n+\t\t\tstrbuf_setlen(sb, sb->len + indent);\n \t\t}\n-\t\tmemcpy(*buf_p + *ofs_p, line, linelen);\n-\t\t*ofs_p += linelen;\n-\t\t(*buf_p)[(*ofs_p)++] = '\\n';\n+\t\tstrbuf_add(sb, line, linelen);\n+\t\tstrbuf_addch(sb, '\\n');\n \t}\n }\n \n-unsigned long pretty_print_commit(enum cmit_fmt fmt,\n-\t\t\t\t  const struct commit *commit,\n-\t\t\t\t  unsigned long len,\n-\t\t\t\t  char **buf_p, unsigned long *space_p,\n-\t\t\t\t  int abbrev, const char *subject,\n-\t\t\t\t  const char *after_subject,\n+void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,\n+\t\t\t\t  struct strbuf *sb, int abbrev,\n+\t\t\t\t  const char *subject, const char *after_subject,\n \t\t\t\t  enum date_mode dmode)\n {\n-\tunsigned long offset = 0;\n \tunsigned long beginning_of_body;\n \tint indent = 4;\n \tconst char *msg = commit->buffer;\n \tint plain_non_ascii = 0;\n \tchar *reencoded;\n \tconst char *encoding;\n-\tchar *buf;\n \n \tif (fmt == CMIT_FMT_USERFORMAT)\n-\t\treturn format_commit_message(commit, msg, buf_p, space_p);\n+\t\treturn format_commit_message(commit, msg, sb);\n \n \tencoding = (git_log_output_encoding\n \t\t    ? git_log_output_encoding\n@@ -1174,7 +1106,6 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \treencoded = logmsg_reencode(commit, encoding);\n \tif (reencoded) {\n \t\tmsg = reencoded;\n-\t\tlen = strlen(reencoded);\n \t}\n \n \tif (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)\n@@ -1189,14 +1120,13 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \tif (fmt == CMIT_FMT_EMAIL && !after_subject) {\n \t\tint i, ch, in_body;\n \n-\t\tfor (in_body = i = 0; (ch = msg[i]) && i < len; i++) {\n+\t\tfor (in_body = i = 0; (ch = msg[i]); i++) {\n \t\t\tif (!in_body) {\n \t\t\t\t/* author could be non 7-bit ASCII but\n \t\t\t\t * the log may be so; skip over the\n \t\t\t\t * header part first.\n \t\t\t\t */\n-\t\t\t\tif (ch == '\\n' &&\n-\t\t\t\t    i + 1 < len && msg[i+1] == '\\n')\n+\t\t\t\tif (ch == '\\n' && msg[i+1] == '\\n')\n \t\t\t\t\tin_body = 1;\n \t\t\t}\n \t\t\telse if (non_ascii(ch)) {\n@@ -1206,59 +1136,44 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\t}\n \t}\n \n-\tpp_header(fmt, abbrev, dmode, encoding,\n-\t\t  commit, &msg, &len,\n-\t\t  &offset, buf_p, space_p);\n+\tpp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);\n \tif (fmt != CMIT_FMT_ONELINE && !subject) {\n-\t\tALLOC_GROW(*buf_p, offset + 20, *space_p);\n-\t\t(*buf_p)[offset++] = '\\n';\n+\t\tstrbuf_addch(sb, '\\n');\n \t}\n \n \t/* Skip excess blank lines at the beginning of body, if any... */\n \tfor (;;) {\n-\t\tint linelen = get_one_line(msg, len);\n+\t\tint linelen = get_one_line(msg);\n \t\tint ll = linelen;\n \t\tif (!linelen)\n \t\t\tbreak;\n \t\tif (!is_empty_line(msg, &ll))\n \t\t\tbreak;\n \t\tmsg += linelen;\n-\t\tlen -= linelen;\n \t}\n \n \t/* These formats treat the title line specially. */\n-\tif (fmt == CMIT_FMT_ONELINE\n-\t    || fmt == CMIT_FMT_EMAIL)\n-\t\tpp_title_line(fmt, &msg, &len, &offset,\n-\t\t\t      buf_p, space_p, indent,\n-\t\t\t      subject, after_subject, encoding,\n-\t\t\t      plain_non_ascii);\n-\n-\tbeginning_of_body = offset;\n-\tif (fmt != CMIT_FMT_ONELINE)\n-\t\tpp_remainder(fmt, &msg, &len, &offset,\n-\t\t\t     buf_p, space_p, indent);\n-\n-\twhile (offset && isspace((*buf_p)[offset-1]))\n-\t\toffset--;\n+\tif (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)\n+\t\tpp_title_line(fmt, &msg, sb, subject,\n+\t\t\t      after_subject, encoding, plain_non_ascii);\n \n-\tALLOC_GROW(*buf_p, offset + 20, *space_p);\n-\tbuf = *buf_p;\n+\tbeginning_of_body = sb->len;\n+\tif (fmt != CMIT_FMT_ONELINE)\n+\t\tpp_remainder(fmt, &msg, sb, indent);\n+\tstrbuf_rtrim(sb);\n \n \t/* Make sure there is an EOLN for the non-oneline case */\n \tif (fmt != CMIT_FMT_ONELINE)\n-\t\tbuf[offset++] = '\\n';\n+\t\tstrbuf_addch(sb, '\\n');\n \n \t/*\n \t * The caller may append additional body text in e-mail\n \t * format.  Make sure we did not strip the blank line\n \t * between the header and the body.\n \t */\n-\tif (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body)\n-\t\tbuf[offset++] = '\\n';\n-\tbuf[offset] = '\\0';\n+\tif (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)\n+\t\tstrbuf_addch(sb, '\\n');\n \tfree(reencoded);\n-\treturn offset;\n }\n \n struct commit *pop_commit(struct commit_list **stack)\n@@ -1337,12 +1252,12 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,\n \t\tnext=next->next;\n \t}\n \t/*\n-         * find the tips\n-         *\n-         * tips are nodes not reachable from any other node in the list\n-         *\n-         * the tips serve as a starting set for the work queue.\n-         */\n+\t * find the tips\n+\t *\n+\t * tips are nodes not reachable from any other node in the list\n+\t *\n+\t * the tips serve as a starting set for the work queue.\n+\t */\n \tnext=*list;\n \tinsert = &work;\n \twhile (next) {\n@@ -1369,9 +1284,9 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,\n \t\t\tif (pn) {\n \t\t\t\t/*\n \t\t\t\t * parents are only enqueued for emission\n-                                 * when all their children have been emitted thereby\n-                                 * guaranteeing topological order.\n-                                 */\n+\t\t\t\t * when all their children have been emitted thereby\n+\t\t\t\t * guaranteeing topological order.\n+\t\t\t\t */\n \t\t\t\tpn->indegree--;\n \t\t\t\tif (!pn->indegree) {\n \t\t\t\t\tif (!lifo)\n@@ -1383,9 +1298,9 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,\n \t\t\tparents=parents->next;\n \t\t}\n \t\t/*\n-                 * work_item is a commit all of whose children\n-                 * have already been emitted. we can emit it now.\n-                 */\n+\t\t * work_item is a commit all of whose children\n+\t\t * have already been emitted. we can emit it now.\n+\t\t */\n \t\t*pptr = work_node->list_item;\n \t\tpptr = &(*pptr)->next;\n \t\t*pptr = NULL;\n@@ -1481,8 +1396,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)\n }\n \n struct commit_list *get_merge_bases(struct commit *one,\n-\t\t\t\t    struct commit *two,\n-                                    int cleanup)\n+\t\t\t\t\tstruct commit *two, int cleanup)\n {\n \tstruct commit_list *list;\n \tstruct commit **rslt;\ndiff --git a/commit.h b/commit.h\nindex 467872e..745f538 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -3,6 +3,7 @@\n \n #include \"object.h\"\n #include \"tree.h\"\n+#include \"strbuf.h\"\n #include \"decorate.h\"\n \n struct commit_list {\n@@ -61,7 +62,10 @@ enum cmit_fmt {\n };\n \n extern enum cmit_fmt get_commit_format(const char *arg);\n-extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char **buf_p, unsigned long *space_p, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);\n+extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,\n+                                struct strbuf *,\n+                                int abbrev, const char *subject,\n+                                const char *after_subject, enum date_mode);\n \n /** Removes the first commit from a list sorted by date, and adds all\n  * of its parents.\ndiff --git a/log-tree.c b/log-tree.c\nindex a642371..5186939 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -79,25 +79,14 @@ static int detect_any_signoff(char *letter, int size)\n \treturn seen_head && seen_name;\n }\n \n-static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,\n-\t\t\t\t    unsigned long at, const char *signoff)\n+static void append_signoff(struct strbuf *sb, const char *signoff)\n {\n \tstatic const char signed_off_by[] = \"Signed-off-by: \";\n \tsize_t signoff_len = strlen(signoff);\n \tint has_signoff = 0;\n \tchar *cp;\n-\tchar *buf;\n-\tunsigned long buf_sz;\n-\n-\tbuf = *buf_p;\n-\tbuf_sz = *buf_sz_p;\n-\tif (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) {\n-\t\tbuf_sz += strlen(signed_off_by) + signoff_len + 3;\n-\t\tbuf = xrealloc(buf, buf_sz);\n-\t\t*buf_p = buf;\n-\t\t*buf_sz_p = buf_sz;\n-\t}\n-\tcp = buf;\n+\n+\tcp = sb->buf;\n \n \t/* First see if we already have the sign-off by the signer */\n \twhile ((cp = strstr(cp, signed_off_by))) {\n@@ -105,29 +94,25 @@ static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,\n \t\thas_signoff = 1;\n \n \t\tcp += strlen(signed_off_by);\n-\t\tif (cp + signoff_len >= buf + at)\n+\t\tif (cp + signoff_len >= sb->buf + sb->len)\n \t\t\tbreak;\n \t\tif (strncmp(cp, signoff, signoff_len))\n \t\t\tcontinue;\n \t\tif (!isspace(cp[signoff_len]))\n \t\t\tcontinue;\n \t\t/* we already have him */\n-\t\treturn at;\n+\t\treturn;\n \t}\n \n \tif (!has_signoff)\n-\t\thas_signoff = detect_any_signoff(buf, at);\n+\t\thas_signoff = detect_any_signoff(sb->buf, sb->len);\n \n \tif (!has_signoff)\n-\t\tbuf[at++] = '\\n';\n-\n-\tstrcpy(buf + at, signed_off_by);\n-\tat += strlen(signed_off_by);\n-\tstrcpy(buf + at, signoff);\n-\tat += signoff_len;\n-\tbuf[at++] = '\\n';\n-\tbuf[at] = 0;\n-\treturn at;\n+\t\tstrbuf_addch(sb, '\\n');\n+\n+\tstrbuf_addstr(sb, signed_off_by);\n+\tstrbuf_add(sb, signoff, signoff_len);\n+\tstrbuf_addch(sb, '\\n');\n }\n \n static unsigned int digits_in_number(unsigned int number)\n@@ -142,14 +127,12 @@ static unsigned int digits_in_number(unsigned int number)\n \n void show_log(struct rev_info *opt, const char *sep)\n {\n-\tchar *msgbuf = NULL;\n-\tunsigned long msgbuf_len = 0;\n+\tstruct strbuf msgbuf;\n \tstruct log_info *log = opt->loginfo;\n \tstruct commit *commit = log->commit, *parent = log->parent;\n \tint abbrev = opt->diffopt.abbrev;\n \tint abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;\n \tconst char *extra;\n-\tint len;\n \tconst char *subject = NULL, *extra_headers = opt->extra_headers;\n \n \topt->loginfo = NULL;\n@@ -288,18 +271,17 @@ void show_log(struct rev_info *opt, const char *sep)\n \t/*\n \t * And then the pretty-printed message itself\n \t */\n-\tlen = pretty_print_commit(opt->commit_format, commit, ~0u,\n-\t\t\t\t  &msgbuf, &msgbuf_len, abbrev, subject,\n-\t\t\t\t  extra_headers, opt->date_mode);\n+\tstrbuf_init(&msgbuf);\n+\tpretty_print_commit(opt->commit_format, commit, &msgbuf,\n+\t\t\t\t  abbrev, subject, extra_headers, opt->date_mode);\n \n \tif (opt->add_signoff)\n-\t\tlen = append_signoff(&msgbuf, &msgbuf_len, len,\n-\t\t\t\t     opt->add_signoff);\n+\t\tappend_signoff(&msgbuf, opt->add_signoff);\n \tif (opt->show_log_size)\n-\t\tprintf(\"log size %i\\n\", len);\n+\t\tprintf(\"log size %i\\n\", (int)msgbuf.len);\n \n-\tprintf(\"%s%s%s\", msgbuf, extra, sep);\n-\tfree(msgbuf);\n+\tprintf(\"%s%s%s\", msgbuf.buf, extra, sep);\n+\tstrbuf_release(&msgbuf);\n }\n \n int log_tree_diff_flush(struct rev_info *opt)\n-- \n1.5.3.1\n"},{"id":"52994","messageId":"851wd9xt98.fsf@lola.goethe.zz","threadId":"9753","inReplyTo":"11892523992038-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers.","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-09-08T11:59:31Z","receivedAt":"2007-09-08T11:59:31Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   Also remove the \"len\" parameter, as:\n>   (1) it was used as a max boundary, and every caller used ~0u\n>   (2) we check for final NUL no matter what, so it doesn't help for speed.\n\nThat sounds like a change that makes improvement of callers impossible\nwhen it is found out that it leads to a performance issue.  Is it only\nthe pretty-print that is affected?\n\n-- \nDavid Kastrup, Kriemhildstr. 15, 44793 Bochum\n"},{"id":"52995","messageId":"20070908121748.GA21864@artemis.corp","threadId":"9753","inReplyTo":"851wd9xt98.fsf@lola.goethe.zz","subject":"Re: [PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T12:17:48Z","receivedAt":"2007-09-08T12:17:48Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Sat, Sep 08, 2007 at 11:59:31AM +0000, David Kastrup wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> >   Also remove the \"len\" parameter, as:\n> >   (1) it was used as a max boundary, and every caller used ~0u\n> >   (2) we check for final NUL no matter what, so it doesn't help for speed.\n> \n> That sounds like a change that makes improvement of callers impossible\n> when it is found out that it leads to a performance issue.  Is it only\n> the pretty-print that is affected?\n\n  I removed the \"len\" argument of pretty_print_commit and all the sub\npp_* functions it uses. This argument was supposed to tell which size\nthe commit message you want to read to format the pretty printing.\n\n  It leads to a lot of code that works like this:\n\n  if (position < len || *msg) /* test if len is overflowed or if we are\n                                 at the end of the string */\n    break;\n\n  This impose us to maintain the len of the message while we make the\n\"msg\" pointer progress, and so on. And it's a limit of what to read in the\ncommit message.\n\nSeeing where pretty_print_commit is used:\n\nbuiltin-branch.c:\t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit,\nbuiltin-log.c:\t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit,\nbuiltin-rev-list.c:\t\tpretty_print_commit(revs.commit_format, commit,\nbuiltin-show-branch.c:\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit,\ncommit.c:void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,\nlog-tree.c:\tpretty_print_commit(opt->commit_format, commit, &msgbuf,\n\n\n  I assume that the user would not be very pleased if we decide to crop\nhis commits logs when he uses git-log. And given that git log in the\nlinux repository on my laptop takes:\n\n  2,13s user 0,06s system 99% cpu 2,213 total\n\nwhen the repo is hot ... I hardly think it can ever be a performance\nissue :)\n\n  But if people disagree I can refactor a patch with the \"len\" argument\nkept.\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"52996","messageId":"20070908122834.GB21864@artemis.corp","threadId":"9753","inReplyTo":"851wd9xt98.fsf@lola.goethe.zz","subject":"Re: [PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T12:28:34Z","receivedAt":"2007-09-08T12:28:34Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On sam, sep 08, 2007 at 11:59:31 +0000, David Kastrup wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> \n> >   Also remove the \"len\" parameter, as:\n> >   (1) it was used as a max boundary, and every caller used ~0u\n> >   (2) we check for final NUL no matter what, so it doesn't help for speed.\n> \n> That sounds like a change that makes improvement of callers impossible\n> when it is found out that it leads to a performance issue.  Is it only\n> the pretty-print that is affected?\n\n  Speaking of performance, here is a small interesting bench:\n\n$ for i in `seq 1 10`; do time git-log >| /dev/null; done\ngit-log >| /dev/null  2,12s user 0,08s system 99% cpu 2,205 total\ngit-log >| /dev/null  2,14s user 0,06s system 99% cpu 2,208 total\ngit-log >| /dev/null  2,12s user 0,08s system 99% cpu 2,205 total\ngit-log >| /dev/null  2,10s user 0,10s system 99% cpu 2,209 total\ngit-log >| /dev/null  2,14s user 0,07s system 99% cpu 2,211 total\ngit-log >| /dev/null  2,11s user 0,09s system 99% cpu 2,210 total\ngit-log >| /dev/null  2,15s user 0,05s system 99% cpu 2,213 total\ngit-log >| /dev/null  2,12s user 0,07s system 99% cpu 2,203 total\ngit-log >| /dev/null  2,13s user 0,06s system 99% cpu 2,204 total\ngit-log >| /dev/null  2,17s user 0,09s system 100% cpu 2,254 total\n\n$ for i in `seq 1 10`; do time ~/dev/scm/git/git-log >| /dev/null; done\n~/dev/scm/git/git-log >| /dev/null  2,06s user 0,11s system 99% cpu 2,185 total\n~/dev/scm/git/git-log >| /dev/null  2,11s user 0,07s system 99% cpu 2,192 total\n~/dev/scm/git/git-log >| /dev/null  2,10s user 0,10s system 99% cpu 2,207 total\n~/dev/scm/git/git-log >| /dev/null  2,10s user 0,08s system 99% cpu 2,188 total\n~/dev/scm/git/git-log >| /dev/null  2,10s user 0,08s system 99% cpu 2,187 total\n~/dev/scm/git/git-log >| /dev/null  2,10s user 0,10s system 100% cpu 2,196 total\n~/dev/scm/git/git-log >| /dev/null  2,08s user 0,11s system 99% cpu 2,195 total\n~/dev/scm/git/git-log >| /dev/null  2,11s user 0,08s system 99% cpu 2,193 total\n~/dev/scm/git/git-log >| /dev/null  2,10s user 0,08s system 100% cpu 2,188 total\n~/dev/scm/git/git-log >| /dev/null  2,12s user 0,07s system 98% cpu 2,213 total\n\n$ git rev-list --all | wc -l\n64271\n\n\n  The underling repository is a not so old linux-2.6 git repository.\ngit-log is the default unstable git-log, (a pristine 1.5.3.1,\npre-new-strbuf).\n\n  ~/dev/scm/git/git-log is obviously the new one with the whole strbuf\npatch series applied. Strbufs definitely made the code more readable (at\nleast it's my impression), here is the proof that it did not affected an\ninch from performance (we even seem to have a marginal 0.5% gain in\nperformance ;p).\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"53000","messageId":"46E2CB4C.8050209@lsrfire.ath.cx","threadId":"9753","inReplyTo":"1189252399433-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 1/3] Add strbuf_rtrim (to remove trailing spaces).","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-09-08T16:18:20Z","receivedAt":"2007-09-08T16:18:20Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Pierre Habouzit schrieb:\n> diff --git a/strbuf.c b/strbuf.c\n> index acc7fc8..565c343 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -28,6 +28,13 @@ void strbuf_grow(struct strbuf *sb, size_t extra) {\n>  \tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n>  }\n>  \n> +void strbuf_rtrim(struct strbuf *sb)\n> +{\n> +    while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))\n> +        sb->len--;\n> +    sb->buf[sb->len] = '\\0';\n> +}\n\nPlease use tabs instead of spaces to indent, just like you did in your\nother patches. :)\n\nRené\n"},{"id":"53002","messageId":"46E2EC88.6000500@lsrfire.ath.cx","threadId":"9753","inReplyTo":"11892523992038-git-send-email-madcoder@debian.org","subject":"Re: [PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers.","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-09-08T18:40:08Z","receivedAt":"2007-09-08T18:40:08Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Pierre Habouzit schrieb:\n>   Also remove the \"len\" parameter, as:\n>   (1) it was used as a max boundary, and every caller used ~0u\n>   (2) we check for final NUL no matter what, so it doesn't help for speed.\n> \n>   As a result most of the pp_* function takes 3 arguments less, and we need\n> a lot less local variables, this makes the code way more readable, and\n> easier to extend if needed.\n> \n>   This patch also fixes some spacing and cosmetic issues.\n> \n> Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n> ---\n>  builtin-branch.c      |   15 +--\n>  builtin-log.c         |   12 +-\n>  builtin-rev-list.c    |   13 +-\n>  builtin-show-branch.c |   13 +-\n>  commit.c              |  330 ++++++++++++++++++-------------------------------\n>  commit.h              |    6 +-\n>  log-tree.c            |   56 +++------\n>  7 files changed, 171 insertions(+), 274 deletions(-)\n\nNice!  I wonder if we should #include strbuf.h from git-compat-util.h\n(just like e.g. string.h) instead of from commit.h, in order to have\nstrbuf available everywhere in git.\n\nPlease be aware of the changes to commit.c already in next which your\npatch conflicts with: format_commit_message() has been exported and is\nused in builtin-archive.c there.\n\nRené\n"},{"id":"53003","messageId":"20070908184907.GA13385@artemis.corp","threadId":"9753","inReplyTo":"46E2EC88.6000500@lsrfire.ath.cx","subject":"Re: [PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T18:49:07Z","receivedAt":"2007-09-08T18:49:07Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Sat, Sep 08, 2007 at 06:40:08PM +0000, René Scharfe wrote:\n> Pierre Habouzit schrieb:\n> >   Also remove the \"len\" parameter, as:\n> >   (1) it was used as a max boundary, and every caller used ~0u\n> >   (2) we check for final NUL no matter what, so it doesn't help for speed.\n> > \n> >   As a result most of the pp_* function takes 3 arguments less, and we need\n> > a lot less local variables, this makes the code way more readable, and\n> > easier to extend if needed.\n> > \n> >   This patch also fixes some spacing and cosmetic issues.\n> > \n> > Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n> > ---\n> >  builtin-branch.c      |   15 +--\n> >  builtin-log.c         |   12 +-\n> >  builtin-rev-list.c    |   13 +-\n> >  builtin-show-branch.c |   13 +-\n> >  commit.c              |  330 ++++++++++++++++++-------------------------------\n> >  commit.h              |    6 +-\n> >  log-tree.c            |   56 +++------\n> >  7 files changed, 171 insertions(+), 274 deletions(-)\n> \n> Nice!  I wonder if we should #include strbuf.h from git-compat-util.h\n> (just like e.g. string.h) instead of from commit.h, in order to have\n> strbuf available everywhere in git.\n> \n> Please be aware of the changes to commit.c already in next which your\n> patch conflicts with: format_commit_message() has been exported and is\n> used in builtin-archive.c there.\n\n  Okay, then I'll hope than Junio will merge the first series and then\nrebase this one on next. If I'm going to propose more of those patches,\nshould I write them rather on next or master (like I do now) ?\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"53017","messageId":"20070908225353.GB13385@artemis.corp","threadId":"9753","inReplyTo":"46E2CB4C.8050209@lsrfire.ath.cx","subject":"Re: [PATCH 1/3] Add strbuf_rtrim (to remove trailing spaces).","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T22:53:53Z","receivedAt":"2007-09-08T22:53:53Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On sam, sep 08, 2007 at 04:18:20 +0000, René Scharfe wrote:\n> Pierre Habouzit schrieb:\n> > diff --git a/strbuf.c b/strbuf.c\n> > index acc7fc8..565c343 100644\n> > --- a/strbuf.c\n> > +++ b/strbuf.c\n> > @@ -28,6 +28,13 @@ void strbuf_grow(struct strbuf *sb, size_t extra) {\n> >  \tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n> >  }\n> >  \n> > +void strbuf_rtrim(struct strbuf *sb)\n> > +{\n> > +    while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))\n> > +        sb->len--;\n> > +    sb->buf[sb->len] = '\\0';\n> > +}\n> \n> Please use tabs instead of spaces to indent, just like you did in your\n> other patches. :)\n\n  yeah, good catch.\n  I've added some more patches tonight, and have added another function\nin strbufs, and thanks to the awsome git rebase -i, this patch\nintegrates this new function as well, so this patch series is obsolete\nalready. I wont repost it until I know if I should rebase it on next\nrather than master though.\n\nCheers,\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"53019","messageId":"20070908234425.GC13385@artemis.corp","threadId":"9753","inReplyTo":"20070908225353.GB13385@artemis.corp","subject":"Re: [PATCH 1/3] Add strbuf_rtrim (to remove trailing spaces).","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-08T23:44:25Z","receivedAt":"2007-09-08T23:44:25Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Sat, Sep 08, 2007 at 10:53:53PM +0000, Pierre Habouzit wrote:\n> On sam, sep 08, 2007 at 04:18:20 +0000, René Scharfe wrote:\n> > Pierre Habouzit schrieb:\n> > > diff --git a/strbuf.c b/strbuf.c\n> > > index acc7fc8..565c343 100644\n> > > --- a/strbuf.c\n> > > +++ b/strbuf.c\n> > > @@ -28,6 +28,13 @@ void strbuf_grow(struct strbuf *sb, size_t extra) {\n> > >  \tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n> > >  }\n> > >  \n> > > +void strbuf_rtrim(struct strbuf *sb)\n> > > +{\n> > > +    while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))\n> > > +        sb->len--;\n> > > +    sb->buf[sb->len] = '\\0';\n> > > +}\n> > \n> > Please use tabs instead of spaces to indent, just like you did in your\n> > other patches. :)\n> \n>   yeah, good catch.\n>   I've added some more patches tonight, and have added another function\n> in strbufs, and thanks to the awsome git rebase -i, this patch\n> integrates this new function as well, so this patch series is obsolete\n> already. I wont repost it until I know if I should rebase it on next\n> rather than master though.\n\n  Okay I'm stupid, Junio already merged my patches in next, doh.\n\n  I've seen the conflict btw, and there is a memory leak (on the format)\nin builtin-archive.c now... but I'm going to fix it (hopefuly) :)\n\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"53555","messageId":"7vabrjqduk.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"1189019923943-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Further strbuf re-engineering.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-19T08:05:55Z","receivedAt":"2007-09-19T08:05:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n> Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n> ---\n>  builtin-apply.c       |   29 ++++++-----------------\n>  builtin-blame.c       |   34 +++++++++-------------------\n>  builtin-commit-tree.c |   59 ++++++++++--------------------------------------\n>  diff.c                |   25 ++++++--------------\n>  4 files changed, 40 insertions(+), 107 deletions(-)\n> ...\n> diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\n> index ccbcbe3..ee74814 100644\n> --- a/builtin-commit-tree.c\n> +++ b/builtin-commit-tree.c\n> @@ -8,42 +8,13 @@\n> ...\n>  /*\n>   * FIXME! Share the code with \"write-tree.c\"\n>   */\n\nYou fixed it.  Remove this comment.\n"},{"id":"53556","messageId":"7v8x73qdtr.fsf@gitster.siamese.dyndns.org","threadId":"9753","inReplyTo":"11890199232128-git-send-email-madcoder@debian.org","subject":"Re: [PATCH] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-19T08:06:24Z","receivedAt":"2007-09-19T08:06:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> writes:\n\n>   This is just cleaner way to deal with strbufs, using its API rather than\n> reinventing it in the module (e.g. strbuf_append_string is just the plain\n> strbuf_addstr function, and it was used to perform what strbuf_addch does\n> anyways).\n> ---\n>  archive-tar.c |   65 ++++++++++++++-------------------------------------------\n>  1 files changed, 16 insertions(+), 49 deletions(-)\n>\n> diff --git a/archive-tar.c b/archive-tar.c\n> index a0763c5..c84d7c0 100644\n> --- a/archive-tar.c\n> +++ b/archive-tar.c\n> @@ -260,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,\n>                             const char *base, int baselen,\n>                             const char *filename, unsigned mode, int stage)\n>  {\n> -\tstatic struct strbuf path;\n> +\tstatic struct strbuf path = STRBUF_INIT;\n>  \tint filenamelen = strlen(filename);\n>  \tvoid *buffer;\n>  \tenum object_type type;\n>  \tunsigned long size;\n>  \n> -\tif (!path.alloc) {\n> -\t\tpath.buf = xmalloc(PATH_MAX);\n> -\t\tpath.alloc = PATH_MAX;\n> -\t\tpath.len = path.eof = 0;\n> -\t}\n> -\tif (path.alloc < baselen + filenamelen + 1) {\n> -\t\tfree(path.buf);\n> -\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n> -\t\tpath.alloc = baselen + filenamelen + 1;\n> -\t}\n> -\tmemcpy(path.buf, base, baselen);\n> -\tmemcpy(path.buf + baselen, filename, filenamelen);\n> -\tpath.len = baselen + filenamelen;\n> -\tpath.buf[path.len] = '\\0';\n> +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n\nWhere are you getting the MAX() macro from?  On my Linux box\nit appears that <sys/params.h> happens to define it but I do not\nthink that is something we can rely upon portably.\n\nMoreover, isn't this allocation wrong?  I thought \"grow\" was\nabout \"we want this much more in addition to the existing\nlength\", not \"reserve at least this much\", and this \"path\" is a\nstatic that will keep the buffer and length from the previous\ninvocation.\n\n> +\tstrbuf_reset(&path);\n> +\tstrbuf_add(&path, base, baselen);\n> +\tstrbuf_add(&path, filename, filenamelen);\n>  \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n> -\t\tstrbuf_append_string(&path, \"/\");\n> +\t\tstrbuf_addch(&path, '/');\n>  \t\tbuffer = NULL;\n>  \t\tsize = 0;\n>  \t} else {\n\nHaving said that, I suspect that the preallocation does not\nreally matter in practice.  How about doing something like:\n\n\tstrbuf_reset(&path);\n        strbuf_grow(&path, PATH_MAX);\n        strbuf_add(&path, base, baselen);\n        strbuf_add(&path, filename, filenamelen);\n"},{"id":"53568","messageId":"20070919083657.GF28205@artemis.corp","threadId":"9753","inReplyTo":"7v8x73qdtr.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Simplify strbuf uses in archive-tar.c using the proper functions.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-19T08:36:57Z","receivedAt":"2007-09-19T08:36:57Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Wed, Sep 19, 2007 at 08:06:24AM +0000, Junio C Hamano wrote:\n> Pierre Habouzit <madcoder@debian.org> writes:\n> > +\tstrbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));\n> \n> Where are you getting the MAX() macro from?  On my Linux box\n> it appears that <sys/params.h> happens to define it but I do not\n> think that is something we can rely upon portably.\n\n  indeed.\n\n> Moreover, isn't this allocation wrong?  I thought \"grow\" was\n> about \"we want this much more in addition to the existing\n> length\", not \"reserve at least this much\", and this \"path\" is a\n> static that will keep the buffer and length from the previous\n> invocation.\n\n  I'm a nitwit, the strbuf_reset() should be done _before_ the grow\nindeed.\n\n> > +\tstrbuf_reset(&path);\n> > +\tstrbuf_add(&path, base, baselen);\n> > +\tstrbuf_add(&path, filename, filenamelen);\n> >  \tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n> > -\t\tstrbuf_append_string(&path, \"/\");\n> > +\t\tstrbuf_addch(&path, '/');\n> >  \t\tbuffer = NULL;\n> >  \t\tsize = 0;\n> >  \t} else {\n> \n> Having said that, I suspect that the preallocation does not\n> really matter in practice.  How about doing something like:\n> \n> \tstrbuf_reset(&path);\n>         strbuf_grow(&path, PATH_MAX);\n>         strbuf_add(&path, base, baselen);\n>         strbuf_add(&path, filename, filenamelen);\n\n  yeah, I was about to propose the same, I'll add a patch in my current\nseries to fix that this way.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"}]}