#include "ProcessRename.h"
#include <stdlib.h>
#include <string.h>


typedef size_t Size;
#define LONG_ALIGN_MASK (sizeof(long) - 1)
#define MEMSET_LOOP_LIMIT 1024          
#define MemSet(start, val, len) \
        do \
        { \
                /* must be void* because we don't know if it is integer aligned yet */ \
                void   *_vstart = (void *) (start); \
                int             _val = (val); \
                Size    _len = (len); \
\
                if ((((long) _vstart) & LONG_ALIGN_MASK) == 0 && \
                        (_len & LONG_ALIGN_MASK) == 0 && \
                        _val == 0 && \
                        _len <= MEMSET_LOOP_LIMIT && \
                        /* \
                         *      If MEMSET_LOOP_LIMIT == 0, optimizer should find \
						 *      the whole "if" false at compile time. \
						*/ \
                        MEMSET_LOOP_LIMIT != 0) \
                { \
                        long *_start = (long *) _vstart; \
                        long *_stop = (long *) ((char *) _start + _len); \
                        while (_start < _stop) \
                                *_start++ = 0; \
                } \
                else \
                        memset(_vstart, _val, _len); \
        } while (0)

#define PS_PADDING '\0'

extern char **environ;
bool            update_process_title = true;

static char *ps_buffer;				/* will point to argv area */
static size_t ps_buffer_size;		/* space determined at run time */
static size_t last_status_len;		/* use to minimize length of clobber */
static size_t ps_buffer_cur_len;	/* nominal strlen(ps_buffer) */
static size_t ps_buffer_fixed_size;	/* size of the constant prefix */

static int      save_argc;
static char **save_argv;

size_t strlcpy(char *dst, const char *src, size_t siz)
{
        char       *d = dst;
        const char *s = src;
        size_t          n = siz;

        /* Copy as many bytes as will fit */
        if (n != 0)
        {
                while (--n != 0)
                {
                        if ((*d++ = *s++) == '\0')
                                break;
                }
        }

        /* Not enough room in dst, add NUL and traverse rest of src */
        if (n == 0)
        {
                if (siz != 0)
                        *d = '\0';                      /* NUL-terminate dst */
                while (*s++)
                        ;
        }

        return (s - src - 1);           /* count does not include NUL */
}


void set_ps_display(const char *activity, bool force)
{     
        /* update_process_title=off disables updates, unless force = true */
        if (!force && !update_process_title)
                return;

        /* no ps display for stand-alone backend */
        //if (!IsUnderPostmaster)
        //        return;

        /* If ps_buffer is a pointer, it might still be null */
        if (!ps_buffer)
                return;
        /* Update ps_buffer to contain both fixed part and activity */
        strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
                        ps_buffer_size - ps_buffer_fixed_size);
        ps_buffer_cur_len = strlen(ps_buffer);

        /* pad unused memory; need only clobber remainder of old status string */
        if (last_status_len > ps_buffer_cur_len)
                MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
                           last_status_len - ps_buffer_cur_len);
        last_status_len = ps_buffer_cur_len;

}


char ** save_ps_display_args(int argc, char **argv)
{
        save_argc = argc;
        save_argv = argv;

        /*
         * If we're going to overwrite the argv area, count the available space.
         * Also move the environment to make additional room.
         */
        {
                char       *end_of_area = NULL;
                char      **new_environ;
                int                     i;

                /*
                 * check for contiguous argv strings
                 */
                for (i = 0; i < argc; i++)
                {
                        if (i == 0 || end_of_area + 1 == argv[i])
                                end_of_area = argv[i] + strlen(argv[i]);
                }

                if (end_of_area == NULL)        /* probably can't happen? */
                {
                        ps_buffer = NULL;
                        ps_buffer_size = 0;
                        return argv;
                }

                /*
                 * check for contiguous environ strings following argv
                 */
                for (i = 0; environ[i] != NULL; i++)
                {
                        if (end_of_area + 1 == environ[i])
                                end_of_area = environ[i] + strlen(environ[i]);
                }

                ps_buffer = argv[0];
                last_status_len = ps_buffer_size = end_of_area - argv[0];

                /*
                 * move the environment out of the way
               */
                new_environ = (char **) malloc((i + 1) * sizeof(char *));
                for (i = 0; environ[i] != NULL; i++)
                        new_environ[i] = strdup(environ[i]);
                new_environ[i] = NULL;
                environ = new_environ;
        }

        /*
         * If we're going to change the original argv[] then make a copy for
         * argument parsing purposes.
         *
         * (NB: do NOT think to remove the copying of argv[], even though
         * postmaster.c finishes looking at argv[] long before we ever consider
         * changing the ps display.  On some platforms, getopt() keeps pointers
         * into the argv array, and will get horribly confused when it is
         * re-called to analyze a subprocess' argument string if the argv storage
         * has been clobbered meanwhile.  Other platforms have other dependencies
         * on argv[].
         */
        {
                char      **new_argv;
                int                     i;

                new_argv = (char **) malloc((argc + 1) * sizeof(char *));
                for (i = 0; i < argc; i++)
                        new_argv[i] = strdup(argv[i]);
                new_argv[argc] = NULL;

                argv = new_argv;
        }

 return argv;

}

