Hi,

At Wed, 18 May 2005 16:20:13 +0900,
Jonathan Paisley wrote in [ruby-talk:143017]:
> > No, it duplicates the argument strings and remains them in the
> > original argv (i.e., pointed from *_NSGetArgv()), but let the
> > entire string area to be pointed by newly allocated argv, which
> > is returned to the caller.
>
> The effect your describe is right, but my point is that set_arg0 (defined
> in ruby.c) needs to operate on the original argv in order to be able to
> change the process name as reported by 'ps'. If set_arg0 sees strdup()-ed
> strings, its changes will have no effect.

Caller's argv is changed but *argv isn't changed.  Pointers pointed by
original argv are changed.  The pointers are not important.

        +-----+-----+-----+-----+-----+
    ,-- |  0  |  1  |  2  |  3  |  4  | <----- original argv
    |   +--|--+--|--+--|--+--|--+--|--+
    |      |     |     |     |     |
    |      V     V     V     V     V
  ,-|- "./argv" "a"   "b"   "c"   NULL  <----- original strings
  | |
~~|~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  | |
  | |  "./argv" "a"   "b"   "c"   NULL  <----- duplicated strings
  | |      A     A     A     A     A
  | |      |     |     |     |     |
  | |   +--|--+--|--+--|--+--|--+--|--+
  | `-> |  0  |  1  |  2  |  3  |  4  | <----- original argv kept
  |     +-----+-----+-----+-----+-----+        in the runtime internal
  |
  `--> "./argv" "a"   "b"   "c"   NULL  <----- original strings
           A     A     A     A     A           in the system area
           |     |     |     |     |
        +--|--+--|--+--|--+--|--+--|--+
        |  0  |  1  |  2  |  3  |  4  | <----- duplicated argv returned
        +-----+-----+-----+-----+-----+          to the caller.


$ cat argv.c
#include "ruby.h"

#undef xmalloc
#define xmalloc malloc

void
ruby_sysinit(argc, argv)
    int *argc;
    char ***argv;
{
    int i, n = *argc, len = 0;
    char **v1 = *argv, **v2 = ALLOC_N(char*, n + 1);
    MEMCPY(v2, v1, char*, n);
    v2[n] = 0;
    for (i = 0; i < n; ++i) {
	v1[i] = strdup(v1[i]);
    }
    *argv = v2;
}

void
dump_argv(name, argc, argv)
    char *name;
    int argc;
    char **argv;
{
    int i;
    printf("%s: argc=%d argv=%p\n", name, argc, argv);
    for (i = 0; i < argc; ++i) {
	char *arg = argv[i];
	printf("argv[%d] = %p \"%s\"\n", i, arg, arg);
    }
}

int main(argc, argv)
    int argc;
    char **argv;
{
    int origargc = argc;
    char **origargv = argv;
    dump_argv("before", argc, argv);
    ruby_sysinit(&argc, &argv);
    dump_argv("after", argc, argv);
    dump_argv("original", origargc, origargv);
    return 0;
}

$ make argv.o && gcc -o argv argv.o

$ ./argv a b c
before: argc=4 argv=0x61813d80
argv[0] = 0x61813dc8 "./argv"
argv[1] = 0x61813df0 "a"
argv[2] = 0x61813e08 "b"
argv[3] = 0x61813e20 "c"
after: argc=4 argv=0xa050008
argv[0] = 0x61813dc8 "./argv"
argv[1] = 0x61813df0 "a"
argv[2] = 0x61813e08 "b"
argv[3] = 0x61813e20 "c"
original: argc=4 argv=0x61813d80
argv[0] = 0xa0505c0 "./argv"
argv[1] = 0xa0505d0 "a"
argv[2] = 0xa0505e0 "b"
argv[3] = 0xa0505f0 "c"

--
Nobu Nakada