bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Bruno Haible <bruno@clisp.org>
To: John Darrington <john@darrington.wattle.id.au>
Cc: bug-gnulib@gnu.org
Subject: Re: [PATCH] tmpdir.c (path_search_alloc): New function.
Date: Sun, 13 Sep 2020 16:07:15 +0200	[thread overview]
Message-ID: <1987219.eVT7o25B4W@omega> (raw)
In-Reply-To: <20200913121125.GA21210@jocasta.intra>

Hi John,

>      > +/* Like path_search, except that TMPL is allocated automatically.
>      > +   TMPL may not be null.  *TMPL must be freed by the caller, when no longer needed.
>      > +   After calling this function *TMPL_LEN will be set to the lenght of *TMPL.  */
>      > +extern int path_search_alloc (char **tmpl, size_t *tmpl_len, const char *dir, const char *pfx,
>      > +                       bool try_tmpdir);
>      
>      The calling convention is odd: If the caller is only meant to use *TMPL and
>      later free() it, why does he need *TMPL_LEN? It seems redundant to return it
>      from this function. And then, if *TMPL is the only output (besides the error
>      condition), why not make it the return value? That is:
>      
>        extern char * path_search_alloc (const char *dir, const char *pfx, bool try_tmpdir);
>      
>      In case of error, this function would return NULL with errno set.
> 
> That would also work.  But I don't think the suggested interface is particularly odd.
> It is very similar to the getline function from libc.

The 'getline' function is not a good model to imitate. Why? Because generally there
should be two supported ways to call such a function
  (a) with a NULL argument - to let the function allocate as much memory as it needs,
  (b) with a stack-allocated buffer as argument - to let the function use that buffer
      if its size is sufficient.
The 'getline' function, as documented [1], does not support the second case.
Its calling convention is thus apparently tailored to the use-case of calling it in
a loop, avoiding memory allocations if a line is shorter than the previous line.
But this is a *very* special use-case, and most functions that people write — including
path_search_alloc — are not like this.

Actually your function supports (a) and (b). But the documentation is lacking and
incorrect:
  - "TMPL may not be null." OK but what can the caller put in TMPL?
  - "*TMPL must be freed by the caller, when no longer needed." Not true.
    In case (b), *TMPL is unchanged, and thus must not be free()d.

How about using this wording, from the GNU libunistring documentation [2]:

  [Functions returning a string result] take a (resultbuf, lengthp) argument
  pair. If resultbuf is not NULL and the result fits into *lengthp units, it
  is put in resultbuf, and resultbuf is returned. Otherwise, a freshly
  allocated string is returned. In both cases, *lengthp is set to the length
  of the returned string. In case of error, NULL is returned and errno is set.

And the prototype that goes with it:

extern char * path_search_alloc (char *resultbuf, size_t *lengthp,
                                 const char *dir, const char *pfx, bool try_tmpdir);

This is simpler than
   extern int path_search_alloc (char **tmpl, size_t *tmpl_len,
                                 const char *dir, const char *pfx, bool try_tmpdir);
in two aspects:
  - It has one less indirection.
  - In the use-cases (a) and (b) the caller has one less local variable.

> I often find that
> when writing code which munges strings, one needs to know the length of a string which
> has already been calculated.   Of course one could simply use strlen to find it, but
> strlen is O(n)

OK, but then make sure that the caller understands what the returned value is.
If you call it 'tmpl_len' everyone would assume that tmpl_len == strlen (tmpl).
But in fast you return strlen (tmpl) + 1. Therefore it should be called
'tmpl_size', not 'tmpl_len'.

>      Also, __path_search is a misnomer now: it does not search anything; it
>      determines the temporary directory in which to place a temporary file.
>      
> So what name would you suggest?  "get_temp_directory" ?

How about renaming
  path_search -> gen_tempfile_template_prealloc
  path_search_alloc -> gen_tempfile_template_alloc
? The first one takes preallocated storage, whereas your function allocates
storage.

Bruno

[1] https://linux.die.net/man/3/getline
[2] https://www.gnu.org/software/libunistring/manual/html_node/Conventions.html



      reply	other threads:[~2020-09-13 14:07 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-13  9:33 [PATCH] tmpdir.c (path_search_alloc): New function John Darrington
2020-09-13 11:12 ` Bruno Haible
2020-09-13 12:11   ` John Darrington
2020-09-13 14:07     ` Bruno Haible [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1987219.eVT7o25B4W@omega \
    --to=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    --cc=john@darrington.wattle.id.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).