Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-24 Thread Silvan Jegen
On Sun, Sep 24, 2017 at 8:57 PM, Mattias Andrée  wrote:
> On Sun, 24 Sep 2017 19:24:10 +0200
> Silvan Jegen  wrote:
>
>> Heyho
>>
>> On Sun, Sep 24, 2017 at 06:28:57PM +0200, Mattias Andrée wrote:
>> > On Sun, 24 Sep 2017 14:08:41 +0200
>> > Silvan Jegen  wrote:
>> >
>> > > > +
>> > > > +   if (!new->len)
>> > > > +   for (i = 0; i < old->len; i++)
>> > > > +   if (old->lines[i].data[-2] != '-')
>> > >
>> > > I think according to the standard, refering to data[-2] invokes undefined
>> > > behaviour, since at this time, data points to the beginning of the array.
>> >
>> > I'm not sure whether it is defined or undefined; I would think that it
>> > defined, but that adding integers larger than INTPTR_MAX is undefined.
>> > I will change to `*(data - 2)` as this is clearly defined.
>>
>> I was referring to
>> https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in-c/3473686#3473686
>> . `*(data -2) is equivalent to 'data[-2]' but since 'data' doesn't point
>> to the second element of the array, I don't think this is valid.
>
> Hi!
>
> I think there has been some misunderstanding here,
> and that we are in agreement that `a[-b]` in it self
> is not invalid, but that question is whether the
> deferenced address is valid. I understand why this
> looks incorrect, `old->lines->data[0]` does not
> actually point to the first character on a line
> in a line but rather to the first character in the
> line that is part of the content of the file that
> hunk patches. For example if the patchfile contains
> the line "- abc", `old->lines->data[0]` is `a`, not
> `-`, because "- " part of the annotations in the
> hunk.

Ah, I missed that. In that case this negative index is ok.


> This should probably be clarified, but you can see
> that this happening just above this code.

Pointing this out in a comment seems like a good idea to me.


> I will look that your other comments later.

Sure!


Cheers,

Silvan



Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-24 Thread Mattias Andrée
On Sun, 24 Sep 2017 19:24:10 +0200
Silvan Jegen  wrote:

> Heyho
> 
> On Sun, Sep 24, 2017 at 06:28:57PM +0200, Mattias Andrée wrote:
> > On Sun, 24 Sep 2017 14:08:41 +0200
> > Silvan Jegen  wrote:
> >   
> > > > +
> > > > +   if (!new->len)
> > > > +   for (i = 0; i < old->len; i++)
> > > > +   if (old->lines[i].data[-2] != '-')
> > > 
> > > I think according to the standard, refering to data[-2] invokes undefined
> > > behaviour, since at this time, data points to the beginning of the array. 
> > >  
> > 
> > I'm not sure whether it is defined or undefined; I would think that it
> > defined, but that adding integers larger than INTPTR_MAX is undefined.
> > I will change to `*(data - 2)` as this is clearly defined.  
> 
> I was referring to
> https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in-c/3473686#3473686
> . `*(data -2) is equivalent to 'data[-2]' but since 'data' doesn't point
> to the second element of the array, I don't think this is valid.

Hi!

I think there has been some misunderstanding here,
and that we are in agreement that `a[-b]` in it self
is not invalid, but that question is whether the
deferenced address is valid. I understand why this
looks incorrect, `old->lines->data[0]` does not
actually point to the first character on a line
in a line but rather to the first character in the
line that is part of the content of the file that
hunk patches. For example if the patchfile contains
the line "- abc", `old->lines->data[0]` is `a`, not
`-`, because "- " part of the annotations in the
hunk.

This should probably be clarified, but you can see
that this happening just above this code.

I will look that your other comments later.


pgpWxkIdgIKQz.pgp
Description: OpenPGP digital signature


Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-24 Thread Silvan Jegen
Heyho

On Sun, Sep 24, 2017 at 06:28:57PM +0200, Mattias Andrée wrote:
> On Sun, 24 Sep 2017 14:08:41 +0200
> Silvan Jegen  wrote:
> 
> > Heyho Mattias!
> > 
> > I had a look at the patch. It's a lot of code (still only about 1/3 of
> > GNU's patch size though) and it was rather hard for me to follow so more
> > review should be done. Find my comments below.
> > 
> > On Sun, Sep 03, 2017 at 07:13:20PM +0200, Mattias Andrée wrote:
> > > +static void
> > > +save_file_cpp(FILE *f, struct file_data *file)
> > > +{
> > > + size_t i, j, n;
> > > + char annot = ' ';
> > > +
> > > + for (i = 0; i <= file->n; i++) {
> > > + if ((n = file->d[i].nold)) {  
> > 
> > In other places you iterate with "i < file->n" (see save_file below for
> > example) so I think this may be an off-by-one error.
> 
> There is an if-statement, that breaks the loop if `i == file->`,
> after this clause, so this should be correct. I'll add blank lines

I saw the break statement but the 'n = file->d[i].nold' will be executed before
reaching that break statement resulting in a segfault when i == file->n.


> around that if-statement to make it clearer.
> 
> > 
> > 
> > > + fprintf(f, "%s\n", annot == '+' ? "#else" : ifndef);
> > > + for (j = 0; j < n; j++) {
> > > + fwriteline(f, file->d[i].old[j]);
> > > + if (missinglf(file->d[i].old[j]))
> > > + fprintf(f, "\n");
> > > + }
> > > + annot = '-';
> > > + }
> > > + if (i == file->n)
> > > + break;
> > > + if (annot == '-')
> > > + fprintf(f, "%s\n", file->d[i].new ? "#else" : "#endif");
> > > + else if (annot == ' ' && file->d[i].new)
> > > + fprintf(f, "%s\n", ifdef);
> > > + else if (annot == '+' && !file->d[i].new)
> > > + fprintf(f, "#endif\n");
> > > + fwriteline(f, file->d[i].line);
> > > + if ((i + 1 < file->n || file->d[i].new) && 
> > > missinglf(file->d[i].line))
> > > + fprintf(f, "\n");
> > > + annot = file->d[i].new ? '+' : ' ';
> > > + }
> > > + if (annot != ' ')
> > > + fprintf(f, "#endif\n");
> > > +}
> > > +
> > > +static void
> > > +parse_hunk_copied(struct hunk *hunk, struct parsed_hunk *parsed)
> > > +{
> > > + struct hunk_content *old = &parsed->old, *new = &parsed->new;
> > > + size_t i = 0, a, b;
> > > + char *p;
> > > +
> > > + free(hunk->head->data);
> > > +
> > > + old->lines = enmalloc(FAILURE, hunk->nlines * sizeof(*old->lines));
> > > + new->lines = enmalloc(FAILURE, hunk->nlines * sizeof(*new->lines));
> > > + parsed->annot = enmalloc(FAILURE, hunk->nlines + 1);
> > > +
> > > + p = hunk->lines[i++].data + 4;
> > > + old->start = strtoul(p, &p, 10);
> > > + old->len = 0;
> > > +
> > > + for (; hunk->lines[i].data[1] == ' '; i++)
> > > + subline(old->lines + old->len++, hunk->lines + i, 2);
> > > +
> > > + p = hunk->lines[i++].data + 4;
> > > + new->start = strtoul(p, &p, 10);
> > > + new->len = 0;
> > > +
> > > + if (old->len) {
> > > + for (; i < hunk->nlines; i++)
> > > + subline(new->lines + new->len++, hunk->lines + i, 2);
> > > + } else {
> > > + for (; i < hunk->nlines; i++) {
> > > + subline(new->lines + new->len++, hunk->lines + i, 2);
> > > + if (hunk->lines[i].data[0] != '+')
> > > + subline(old->lines + old->len++, hunk->lines + 
> > > i, 2);
> > > + }
> > > + }  
> > 
> > I think this if-else block can be rewritten like this.
> > 
> > for (; i < hunk->nlines; i++) {
> > subline(new->lines + new->len++, hunk->lines + i, 2);
> > if (old->len == 0 && hunk->lines[i].data[0] != '+')
> > subline(old->lines + old->len++, hunk->lines + i, 2);
> > }
> 
> I will use `!old->len` instead of `old->len == 0`.
> 
> > 
> > 
> > > +
> > > + if (!new->len)
> > > + for (i = 0; i < old->len; i++)
> > > + if (old->lines[i].data[-2] != '-')  
> > 
> > I think according to the standard, refering to data[-2] invokes undefined
> > behaviour, since at this time, data points to the beginning of the array.
> 
> I'm not sure whether it is defined or undefined; I would think that it
> defined, but that adding integers larger than INTPTR_MAX is undefined.
> I will change to `*(data - 2)` as this is clearly defined.

I was referring to
https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in-c/3473686#3473686
. `*(data -2) is equivalent to 'data[-2]' but since 'data' doesn't point
to the second element of the array, I don't think this is valid.


> > 
> > 
> > > + new->lines[new->len++] = old->lines[i];
> > > +
> > > +#define OLDLINE  a < old->len && old->lines[a].data[-2]
> > > +#define NEWLINE  b < new->len && new->lines[b].data[-2]
> > > +
> > > + for (i = a 

Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-24 Thread Mattias Andrée
On Sun, 24 Sep 2017 14:08:41 +0200
Silvan Jegen  wrote:

> Heyho Mattias!
> 
> I had a look at the patch. It's a lot of code (still only about 1/3 of
> GNU's patch size though) and it was rather hard for me to follow so more
> review should be done. Find my comments below.
> 
> On Sun, Sep 03, 2017 at 07:13:20PM +0200, Mattias Andrée wrote:
> > +static void
> > +save_file_cpp(FILE *f, struct file_data *file)
> > +{
> > +   size_t i, j, n;
> > +   char annot = ' ';
> > +
> > +   for (i = 0; i <= file->n; i++) {
> > +   if ((n = file->d[i].nold)) {  
> 
> In other places you iterate with "i < file->n" (see save_file below for
> example) so I think this may be an off-by-one error.

There is an if-statement, that breaks the loop if `i == file->`,
after this clause, so this should be correct. I'll add blank lines
around that if-statement to make it clearer.

> 
> 
> > +   fprintf(f, "%s\n", annot == '+' ? "#else" : ifndef);
> > +   for (j = 0; j < n; j++) {
> > +   fwriteline(f, file->d[i].old[j]);
> > +   if (missinglf(file->d[i].old[j]))
> > +   fprintf(f, "\n");
> > +   }
> > +   annot = '-';
> > +   }
> > +   if (i == file->n)
> > +   break;
> > +   if (annot == '-')
> > +   fprintf(f, "%s\n", file->d[i].new ? "#else" : "#endif");
> > +   else if (annot == ' ' && file->d[i].new)
> > +   fprintf(f, "%s\n", ifdef);
> > +   else if (annot == '+' && !file->d[i].new)
> > +   fprintf(f, "#endif\n");
> > +   fwriteline(f, file->d[i].line);
> > +   if ((i + 1 < file->n || file->d[i].new) && 
> > missinglf(file->d[i].line))
> > +   fprintf(f, "\n");
> > +   annot = file->d[i].new ? '+' : ' ';
> > +   }
> > +   if (annot != ' ')
> > +   fprintf(f, "#endif\n");
> > +}
> > +
> > +static void
> > +parse_hunk_copied(struct hunk *hunk, struct parsed_hunk *parsed)
> > +{
> > +   struct hunk_content *old = &parsed->old, *new = &parsed->new;
> > +   size_t i = 0, a, b;
> > +   char *p;
> > +
> > +   free(hunk->head->data);
> > +
> > +   old->lines = enmalloc(FAILURE, hunk->nlines * sizeof(*old->lines));
> > +   new->lines = enmalloc(FAILURE, hunk->nlines * sizeof(*new->lines));
> > +   parsed->annot = enmalloc(FAILURE, hunk->nlines + 1);
> > +
> > +   p = hunk->lines[i++].data + 4;
> > +   old->start = strtoul(p, &p, 10);
> > +   old->len = 0;
> > +
> > +   for (; hunk->lines[i].data[1] == ' '; i++)
> > +   subline(old->lines + old->len++, hunk->lines + i, 2);
> > +
> > +   p = hunk->lines[i++].data + 4;
> > +   new->start = strtoul(p, &p, 10);
> > +   new->len = 0;
> > +
> > +   if (old->len) {
> > +   for (; i < hunk->nlines; i++)
> > +   subline(new->lines + new->len++, hunk->lines + i, 2);
> > +   } else {
> > +   for (; i < hunk->nlines; i++) {
> > +   subline(new->lines + new->len++, hunk->lines + i, 2);
> > +   if (hunk->lines[i].data[0] != '+')
> > +   subline(old->lines + old->len++, hunk->lines + 
> > i, 2);
> > +   }
> > +   }  
> 
> I think this if-else block can be rewritten like this.
> 
>   for (; i < hunk->nlines; i++) {
>   subline(new->lines + new->len++, hunk->lines + i, 2);
>   if (old->len == 0 && hunk->lines[i].data[0] != '+')
>   subline(old->lines + old->len++, hunk->lines + i, 2);
>   }

I will use `!old->len` instead of `old->len == 0`.

> 
> 
> > +
> > +   if (!new->len)
> > +   for (i = 0; i < old->len; i++)
> > +   if (old->lines[i].data[-2] != '-')  
> 
> I think according to the standard, refering to data[-2] invokes undefined
> behaviour, since at this time, data points to the beginning of the array.

I'm not sure whether it is defined or undefined; I would think that it
defined, but that adding integers larger than INTPTR_MAX is undefined.
I will change to `*(data - 2)` as this is clearly defined.

> 
> 
> > +   new->lines[new->len++] = old->lines[i];
> > +
> > +#define OLDLINE  a < old->len && old->lines[a].data[-2]
> > +#define NEWLINE  b < new->len && new->lines[b].data[-2]
> > +
> > +   for (i = a = b = 0; a < old->len || b < new->len;) {
> > +   if (OLDLINE == '-')  parsed->annot[i++] = '-', a++;
> > +   if (NEWLINE == '+')  parsed->annot[i++] = '+', b++;
> > +   while (OLDLINE == ' ' && NEWLINE == ' ')
> > +   parsed->annot[i++] = ' ', a++, b++;
> > +   while (OLDLINE == '!')  parsed->annot[i++] = '<', a++;
> > +   while (NEWLINE == '!')  parsed->annot[i++] = '>', b++;
> > +   }
> > +   parsed->annot[i] = 0;  
> > +}
> > +
> > +static void
> > +apply_contiguous_edit(struct file_data *f, size_t ln, size_t rm, size_t 
> > ad, struct li

Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-24 Thread Silvan Jegen
Heyho Mattias!

I had a look at the patch. It's a lot of code (still only about 1/3 of
GNU's patch size though) and it was rather hard for me to follow so more
review should be done. Find my comments below.

On Sun, Sep 03, 2017 at 07:13:20PM +0200, Mattias Andrée wrote:
> Signed-off-by: Mattias Andrée 
> ---
>  Makefile   |2 +
>  README |1 +
>  TODO   |1 -
>  libutil/asprintf.c |   74 +++
>  libutil/getlines.c |   17 +-
>  patch.1|  250 +++
>  patch.c| 1835 
> 
>  text.h |4 +-
>  util.h |5 +
>  9 files changed, 2182 insertions(+), 7 deletions(-)
>  create mode 100644 libutil/asprintf.c
>  create mode 100644 patch.1
>  create mode 100644 patch.c
> 
> diff --git a/Makefile b/Makefile
> index 1c39fef..014db74 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -45,6 +45,7 @@ LIBUTFSRC =\
>  
>  LIBUTIL = libutil.a
>  LIBUTILSRC =\
> + libutil/asprintf.c\
>   libutil/concat.c\
>   libutil/cp.c\
>   libutil/crypt.c\
> @@ -132,6 +133,7 @@ BIN =\
>   nohup\
>   od\
>   paste\
> + patch\
>   pathchk\
>   printenv\
>   printf\
> diff --git a/README b/README
> index da2e500..6c94f2f 100644
> --- a/README
> +++ b/README
> @@ -59,6 +59,7 @@ The following tools are implemented:
>  0#*|o nl  .
>  0=*|o nohup   .
>  0=*|o od  .
> +0=patch   .
>  0#* o pathchk .
>   #*|o paste   .
>  0=*|x printenv.
> diff --git a/TODO b/TODO
> index 5edb8a3..fe2344e 100644
> --- a/TODO
> +++ b/TODO
> @@ -8,7 +8,6 @@ awk
>  bc
>  diff
>  ed manpage
> -patch
>  stty
>  
>  If you are looking for some work to do on sbase, another option is to
> diff --git a/libutil/asprintf.c b/libutil/asprintf.c
> new file mode 100644
> index 000..929ed09
> --- /dev/null
> +++ b/libutil/asprintf.c
> @@ -0,0 +1,74 @@
> +/* See LICENSE file for copyright and license details. */
> +#include 
> +#include 
> +#include 
> +
> +#include "../util.h"
> +
> +static int xenvasprintf(int, char **, const char *, va_list);
> +
> +int
> +asprintf(char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = xenvasprintf(-1, strp, fmt, ap);
> + va_end(ap);
> +
> + return ret;
> +}
> +
> +int
> +easprintf(char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = xenvasprintf(1, strp, fmt, ap);
> + va_end(ap);
> +
> + return ret;
> +}
> +
> +int
> +enasprintf(int status, char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = xenvasprintf(status, strp, fmt, ap);
> + va_end(ap);
> +
> + return ret;
> +}
> +
> +int
> +xenvasprintf(int status, char **strp, const char *fmt, va_list ap)
> +{
> + int ret;
> + va_list ap2;
> +
> + va_copy(ap2, ap);
> + ret = vsnprintf(0, 0, fmt, ap2);
> + va_end(ap2);
> + if (ret < 0) {
> + if (status >= 0)
> + enprintf(status, "vsnprintf:");
> + *strp = 0;
> + return -1;
> + }
> +
> + *strp = malloc(ret + 1);
> + if (!*strp) {
> + if (status >= 0)
> + enprintf(status, "malloc:");
> + return -1;
> + }
> +
> + vsprintf(*strp, fmt, ap);
> + return ret;
> +}
> diff --git a/libutil/getlines.c b/libutil/getlines.c
> index b912769..9af7684 100644
> --- a/libutil/getlines.c
> +++ b/libutil/getlines.c
> @@ -7,7 +7,7 @@
>  #include "../util.h"
>  
>  void
> -getlines(FILE *fp, struct linebuf *b)
> +ngetlines(int status, FILE *fp, struct linebuf *b)
>  {
>   char *line = NULL;
>   size_t size = 0, linelen = 0;
> @@ -16,17 +16,24 @@ getlines(FILE *fp, struct linebuf *b)
>   while ((len = getline(&line, &size, fp)) > 0) {
>   if (++b->nlines > b->capacity) {
>   b->capacity += 512;
> - b->lines = erealloc(b->lines, b->capacity * 
> sizeof(*b->lines));
> + b->lines = enrealloc(status, b->lines, b->capacity * 
> sizeof(*b->lines));
>   }
>   linelen = len;
> - b->lines[b->nlines - 1].data = memcpy(emalloc(linelen + 1), 
> line, linelen + 1);
> + b->lines[b->nlines - 1].data = memcpy(enmalloc(status, linelen 
> + 1), line, linelen + 1);
>   b->lines[b->nlines - 1].len = linelen;
>   }
>   free(line);
> - if (b->lines && b->nlines && linelen && b->lines[b->nlines - 
> 1].data[linelen - 1] != '\n') {
> - b->lines[b->nlines - 1].data = erealloc(b->lines[b->nlines - 
> 1].data, linelen + 2);
> + b->nolf = b->lines && b->nlines && linelen && b->lines[b->nlines - 
> 1].data[linelen - 1] != '\n';
> + if (b->nolf) {
> + b->lines[b->nlines - 1].data = enrealloc(status, 

Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-11 Thread Silvan Jegen
On Mon, Sep 11, 2017 at 08:57:02PM +0200, Mattias Andrée wrote:
> On Mon, 11 Sep 2017 20:09:33 +0200
> Silvan Jegen  wrote:
> 
> >> +when comparing directories. If however, the  
> > 
> > There should probably be an additional comma like this:
> > 
> > "If, however, the file..."
> 
> I think “However, if the file...” is better.

Sounds good to me!


> > > +portion of a patch. A patch is a signal
> > > +file-comparison output from  
> > 
> > Not sure what a "signal file-comparison output" is... is this official
> > POSIX/patch terminology?
> 
> s/signal/singel/, so a patch file includes
> a patchset with is a number of patches, one
> per file in the patch file.

Haha, I totally didn't think of that...

 
> >> +Symbolic links are treated as regular files,
> >> +provided that they lead to regular files.  
> > 
> > maybe s/lead/link/ ?
> 
> Not sure, perhaps “link” sounds more natural,
> but for me, ”link” means we are talking about
> the step and not the final step when following
> the link. However, I will add this change.

I think both are understandable but the term "link" for symbolic links
is definitely the more common one, I would say.


signature.asc
Description: PGP signature


Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-11 Thread Mattias Andrée
On Mon, 11 Sep 2017 20:09:33 +0200
Silvan Jegen  wrote:

>> +when comparing directories. If however, the  
> 
> There should probably be an additional comma like this:
> 
> "If, however, the file..."

I think “However, if the file...” is better.

> > +portion of a patch. A patch is a signal
> > +file-comparison output from  
> 
> Not sure what a "signal file-comparison output" is... is this official
> POSIX/patch terminology?

s/signal/singel/, so a patch file includes
a patchset with is a number of patches, one
per file in the patch file.

>> +Symbolic links are treated as regular files,
>> +provided that they lead to regular files.  
> 
> maybe s/lead/link/ ?

Not sure, perhaps “link” sounds more natural,
but for me, ”link” means we are talking about
the step and not the final step when following
the link. However, I will add this change.


pgpFOH92wIueQ.pgp
Description: OpenPGP digital signature


Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-11 Thread Silvan Jegen
Hi Mattias!

Thanks for (the) patch! :P

Some comments below. For now I only managed to look at whitespace issues
in the patch and suggest some corrections for spelling/grammar issues
in the man page text. I hope to get around looking at the code in the
near future.

On Sun, Sep 03, 2017 at 07:13:20PM +0200, Mattias Andrée wrote:
> Signed-off-by: Mattias Andrée 
> ---
>  Makefile   |2 +
>  README |1 +
>  TODO   |1 -
>  libutil/asprintf.c |   74 +++
>  libutil/getlines.c |   17 +-
>  patch.1|  250 +++
>  patch.c| 1835 
> 
>  text.h |4 +-
>  util.h |5 +
>  9 files changed, 2182 insertions(+), 7 deletions(-)
>  create mode 100644 libutil/asprintf.c
>  create mode 100644 patch.1
>  create mode 100644 patch.c
> 
> diff --git a/Makefile b/Makefile
> index 1c39fef..014db74 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -45,6 +45,7 @@ LIBUTFSRC =\
>  
>  LIBUTIL = libutil.a
>  LIBUTILSRC =\
> + libutil/asprintf.c\
>   libutil/concat.c\
>   libutil/cp.c\
>   libutil/crypt.c\
> @@ -132,6 +133,7 @@ BIN =\
>   nohup\
>   od\
>   paste\
> + patch\
>   pathchk\
>   printenv\
>   printf\
> diff --git a/README b/README
> index da2e500..6c94f2f 100644
> --- a/README
> +++ b/README
> @@ -59,6 +59,7 @@ The following tools are implemented:
>  0#*|o nl  .
>  0=*|o nohup   .
>  0=*|o od  .
> +0=patch   .
>  0#* o pathchk .
>   #*|o paste   .
>  0=*|x printenv.
> diff --git a/TODO b/TODO
> index 5edb8a3..fe2344e 100644
> --- a/TODO
> +++ b/TODO
> @@ -8,7 +8,6 @@ awk
>  bc
>  diff
>  ed manpage
> -patch
>  stty
>  
>  If you are looking for some work to do on sbase, another option is to
> diff --git a/libutil/asprintf.c b/libutil/asprintf.c
> new file mode 100644
> index 000..929ed09
> --- /dev/null
> +++ b/libutil/asprintf.c
> @@ -0,0 +1,74 @@
> +/* See LICENSE file for copyright and license details. */
> +#include 
> +#include 
> +#include 
> +
> +#include "../util.h"
> +
> +static int xenvasprintf(int, char **, const char *, va_list);
> +
> +int
> +asprintf(char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = xenvasprintf(-1, strp, fmt, ap);
> + va_end(ap);
> +
> + return ret;
> +}
> +
> +int
> +easprintf(char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = xenvasprintf(1, strp, fmt, ap);
> + va_end(ap);
> +
> + return ret;
> +}
> +
> +int
> +enasprintf(int status, char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = xenvasprintf(status, strp, fmt, ap);
> + va_end(ap);
> +
> + return ret;
> +}
> +
> +int
> +xenvasprintf(int status, char **strp, const char *fmt, va_list ap)
> +{
> + int ret;
> + va_list ap2;
> +
> + va_copy(ap2, ap);
> + ret = vsnprintf(0, 0, fmt, ap2);
> + va_end(ap2);
> + if (ret < 0) {
> + if (status >= 0)
> + enprintf(status, "vsnprintf:");
> + *strp = 0;
> + return -1;
> + }
> +
> + *strp = malloc(ret + 1);
> + if (!*strp) {
> + if (status >= 0)
> + enprintf(status, "malloc:");
> + return -1;
> + }
> +
> + vsprintf(*strp, fmt, ap);
> + return ret;
> +}
> diff --git a/libutil/getlines.c b/libutil/getlines.c
> index b912769..9af7684 100644
> --- a/libutil/getlines.c
> +++ b/libutil/getlines.c
> @@ -7,7 +7,7 @@
>  #include "../util.h"
>  
>  void
> -getlines(FILE *fp, struct linebuf *b)
> +ngetlines(int status, FILE *fp, struct linebuf *b)
>  {
>   char *line = NULL;
>   size_t size = 0, linelen = 0;
> @@ -16,17 +16,24 @@ getlines(FILE *fp, struct linebuf *b)
>   while ((len = getline(&line, &size, fp)) > 0) {
>   if (++b->nlines > b->capacity) {
>   b->capacity += 512;
> - b->lines = erealloc(b->lines, b->capacity * 
> sizeof(*b->lines));
> + b->lines = enrealloc(status, b->lines, b->capacity * 
> sizeof(*b->lines));
>   }
>   linelen = len;
> - b->lines[b->nlines - 1].data = memcpy(emalloc(linelen + 1), 
> line, linelen + 1);
> + b->lines[b->nlines - 1].data = memcpy(enmalloc(status, linelen 
> + 1), line, linelen + 1);
>   b->lines[b->nlines - 1].len = linelen;
>   }
>   free(line);
> - if (b->lines && b->nlines && linelen && b->lines[b->nlines - 
> 1].data[linelen - 1] != '\n') {
> - b->lines[b->nlines - 1].data = erealloc(b->lines[b->nlines - 
> 1].data, linelen + 2);
> + b->nolf = b->lines && b->nlines && linelen && b->lines[b->nlines - 
> 1].data[linelen - 1] != '\n';
> + if (b->nolf) {
> +  

Re: [hackers] [PATCH][sbase] Add patch(1)

2017-09-04 Thread Laslo Hunhold
On Sun,  3 Sep 2017 19:13:20 +0200
Mattias Andrée  wrote:

Dear Mattias,

> 

I saw that you had sent the patch(1) patch already back in March 2016.
Hopefully we can review it accordingly now and Michael Forney merge it!

With best regards

Laslo Hunhold

-- 
Laslo Hunhold 



[hackers] [PATCH][sbase] Add patch(1)

2017-09-03 Thread Mattias Andrée
Signed-off-by: Mattias Andrée 
---
 Makefile   |2 +
 README |1 +
 TODO   |1 -
 libutil/asprintf.c |   74 +++
 libutil/getlines.c |   17 +-
 patch.1|  250 +++
 patch.c| 1835 
 text.h |4 +-
 util.h |5 +
 9 files changed, 2182 insertions(+), 7 deletions(-)
 create mode 100644 libutil/asprintf.c
 create mode 100644 patch.1
 create mode 100644 patch.c

diff --git a/Makefile b/Makefile
index 1c39fef..014db74 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ LIBUTFSRC =\
 
 LIBUTIL = libutil.a
 LIBUTILSRC =\
+   libutil/asprintf.c\
libutil/concat.c\
libutil/cp.c\
libutil/crypt.c\
@@ -132,6 +133,7 @@ BIN =\
nohup\
od\
paste\
+   patch\
pathchk\
printenv\
printf\
diff --git a/README b/README
index da2e500..6c94f2f 100644
--- a/README
+++ b/README
@@ -59,6 +59,7 @@ The following tools are implemented:
 0#*|o nl  .
 0=*|o nohup   .
 0=*|o od  .
+0=patch   .
 0#* o pathchk .
  #*|o paste   .
 0=*|x printenv.
diff --git a/TODO b/TODO
index 5edb8a3..fe2344e 100644
--- a/TODO
+++ b/TODO
@@ -8,7 +8,6 @@ awk
 bc
 diff
 ed manpage
-patch
 stty
 
 If you are looking for some work to do on sbase, another option is to
diff --git a/libutil/asprintf.c b/libutil/asprintf.c
new file mode 100644
index 000..929ed09
--- /dev/null
+++ b/libutil/asprintf.c
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+#include 
+#include 
+#include 
+
+#include "../util.h"
+
+static int xenvasprintf(int, char **, const char *, va_list);
+
+int
+asprintf(char **strp, const char *fmt, ...)
+{
+   va_list ap;
+   int ret;
+
+   va_start(ap, fmt);
+   ret = xenvasprintf(-1, strp, fmt, ap);
+   va_end(ap);
+
+   return ret;
+}
+
+int
+easprintf(char **strp, const char *fmt, ...)
+{
+   va_list ap;
+   int ret;
+
+   va_start(ap, fmt);
+   ret = xenvasprintf(1, strp, fmt, ap);
+   va_end(ap);
+
+   return ret;
+}
+
+int
+enasprintf(int status, char **strp, const char *fmt, ...)
+{
+   va_list ap;
+   int ret;
+
+   va_start(ap, fmt);
+   ret = xenvasprintf(status, strp, fmt, ap);
+   va_end(ap);
+
+   return ret;
+}
+
+int
+xenvasprintf(int status, char **strp, const char *fmt, va_list ap)
+{
+   int ret;
+   va_list ap2;
+
+   va_copy(ap2, ap);
+   ret = vsnprintf(0, 0, fmt, ap2);
+   va_end(ap2);
+   if (ret < 0) {
+   if (status >= 0)
+   enprintf(status, "vsnprintf:");
+   *strp = 0;
+   return -1;
+   }
+
+   *strp = malloc(ret + 1);
+   if (!*strp) {
+   if (status >= 0)
+   enprintf(status, "malloc:");
+   return -1;
+   }
+
+   vsprintf(*strp, fmt, ap);
+   return ret;
+}
diff --git a/libutil/getlines.c b/libutil/getlines.c
index b912769..9af7684 100644
--- a/libutil/getlines.c
+++ b/libutil/getlines.c
@@ -7,7 +7,7 @@
 #include "../util.h"
 
 void
-getlines(FILE *fp, struct linebuf *b)
+ngetlines(int status, FILE *fp, struct linebuf *b)
 {
char *line = NULL;
size_t size = 0, linelen = 0;
@@ -16,17 +16,24 @@ getlines(FILE *fp, struct linebuf *b)
while ((len = getline(&line, &size, fp)) > 0) {
if (++b->nlines > b->capacity) {
b->capacity += 512;
-   b->lines = erealloc(b->lines, b->capacity * 
sizeof(*b->lines));
+   b->lines = enrealloc(status, b->lines, b->capacity * 
sizeof(*b->lines));
}
linelen = len;
-   b->lines[b->nlines - 1].data = memcpy(emalloc(linelen + 1), 
line, linelen + 1);
+   b->lines[b->nlines - 1].data = memcpy(enmalloc(status, linelen 
+ 1), line, linelen + 1);
b->lines[b->nlines - 1].len = linelen;
}
free(line);
-   if (b->lines && b->nlines && linelen && b->lines[b->nlines - 
1].data[linelen - 1] != '\n') {
-   b->lines[b->nlines - 1].data = erealloc(b->lines[b->nlines - 
1].data, linelen + 2);
+   b->nolf = b->lines && b->nlines && linelen && b->lines[b->nlines - 
1].data[linelen - 1] != '\n';
+   if (b->nolf) {
+   b->lines[b->nlines - 1].data = enrealloc(status, 
b->lines[b->nlines - 1].data, linelen + 2);
b->lines[b->nlines - 1].data[linelen] = '\n';
b->lines[b->nlines - 1].data[linelen + 1] = '\0';
b->lines[b->nlines - 1].len++;
}
 }
+
+void
+getlines(FILE *fp, struct linebuf *b)
+{
+   ngetlines(1, fp, b);
+}
diff --git a/patch.1 b/patch.1
new file mode 100644
index 000..df2bf63
--- /dev/null
+++ b/patch.1
@@ -0,0 +1,250 @@
+.Dd 2016-03-20
+.Dt PATCH 1
+.Os sbase
+.Sh NAME
+.Nm patch