bug-findutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: ARG_MAX


From: James Youngman
Subject: Re: ARG_MAX
Date: Thu, 26 Apr 2007 10:23:33 +0100

On 4/26/07, Leslie P. Polzer <address@hidden> wrote:

If there's sufficient time, the linear approach can be substituted
by a binary one then (while still doing it only on-demand, of course).

I like  your idea of separating the strategy (making decisions about
whether to exec now and start again, or add this argument to the list)
from the nuts and bolts of the implementation.  Perhaps we couls
separate the buildcmd.c implementation into the existing part that
handles initial arguments, substitution, etc from the part that makes
decisions whether or not to call exec now (which would need to be
factored out).   Perhaps something like this:-


struct bc_strategy_handler
{
 /* Initialise the strategy handler and return an opaque context */
 void * (initialise)(const char *environment_strings);

 /* Cleanup */
 void (*destroy)(void *context);

 /* Indicate if we think there is space for this arg in the arg list */
 bool (*space_for_arg)(size_t n_args, size_t tot_len, size_t
this_arg_len, void* context);

 /* Remember that an exec with these properties failed (with E2BIG)
or succeeded*/
 void (*remember_exec_result)(bool success, size_t n_args, size_t
tot_len, void *context);

 /* Given an existing argument list, suggest a place to split it. */
 size_t (*suggest_argv_split)(size_t n_args, const char * const
args[], void *context);
};

The linear implementation could just be something like this (I haven't
compiled let alone tested this):

struct lincontext
{
 size_t greatest_success;
 size_t least_failure;
 sizet_t envsize;
 size_t step;
};

static size_t
measure(const char * const svec)
{
 size_t n = 0u;
 if (svec)
 {
   while (*svec)
   {
     n += strlen(*svec);
     ++svec;
   }
  return n;
 }
}


static void *
lin_initialise(const char *environment_strings)
{
 struct lincontext *p = malloc(sizeof(struct lincontext));
 p->greatest_success = 1u;
 p->least_failure = SIZE_MAX;
 p->envsize = measure(environment_strings);
 p->step = 64u * 1024u; /* 64 KiB */
}

static bool
lin_space_for_arg(size_t n_args, size_t tot_len, size_t this_arg_len,
void* context)
{
 const struct lincontext *p = context;
 if (p->envsize + tot_len < p->least_failure)
   return true;
 else
  return false;
}

static void
lin_remember_exec_result(bool success, size_t n_args, size_t arg_len,
void *context)
{
 struct lincontext *p = context;
 size_t tot_len = arg_len + p->envsize;
 if (success)
 {
   if (tot_len > p->greatest_success)
   {
      p->greatest_success = tot_len;
   }
 }
 else
 {
   if (tot_len < p->least_failure)
   {
     p->least_failure = tot_len;
    }
  }
}

size_t lin_suggest_argv_split(size_t n_args, const char * const
args[], void *context)
{
 const struct lincontext *p = context;
 sizr_t i = 0u;
 size_t totlen = p->envsize, len;
 while (totlen < p->greatest_success)
 {
    /* there could be an off-by-one error here, I haven't tested the code */
    len = strlen(args[i]);
    totlen += len;
    ++i;
 }
 len = strlen(args[i]);
 if (totlen + p->envsize + len > p->least_failure)
 {
    /* not guaranteed to succeed, try it out anyway */
    ++i;
 }
 return i;
}

const struct bc_strategy_handler linear_strategy =
{
 lin_initialise,
 free,
 lin_space_for_arg,
 lin_remember_exec_result,
 lin_suggest_argv_split
};




reply via email to

[Prev in Thread] Current Thread [Next in Thread]