System.c 6.66 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3 4 5 6 7 8
#include "kwsysPrivate.h"
#include KWSYS_HEADER(System.h)

/* Work-around CMake dependency scanning limitation.  This must
   duplicate the above list of headers.  */
#if 0
9
#  include "System.h.in"
10 11
#endif

12
#include <ctype.h>  /* isspace */
13 14
#include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* malloc, free */
Brad King's avatar
Brad King committed
15
#include <string.h> /* memcpy */
16 17 18

#include <stdio.h>

19 20 21 22 23 24
#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
typedef ptrdiff_t kwsysSystem_ptrdiff_t;
#else
typedef int kwsysSystem_ptrdiff_t;
#endif

25
static int kwsysSystem__AppendByte(char* local, char** begin, char** end,
26 27 28
                                   int* size, char c)
{
  /* Allocate space for the character.  */
29
  if ((*end - *begin) >= *size) {
30
    kwsysSystem_ptrdiff_t length = *end - *begin;
31 32
    char* newBuffer = (char*)malloc((size_t)(*size * 2));
    if (!newBuffer) {
33
      return 0;
34 35 36
    }
    memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char));
    if (*begin != local) {
37
      free(*begin);
38
    }
39 40 41
    *begin = newBuffer;
    *end = *begin + length;
    *size *= 2;
42
  }
43 44 45 46 47 48

  /* Store the character.  */
  *(*end)++ = c;
  return 1;
}

49 50
static int kwsysSystem__AppendArgument(char** local, char*** begin,
                                       char*** end, int* size, char* arg_local,
51 52 53 54
                                       char** arg_begin, char** arg_end,
                                       int* arg_size)
{
  /* Append a null-terminator to the argument string.  */
55 56
  if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size,
                               '\0')) {
57
    return 0;
58
  }
59 60

  /* Allocate space for the argument pointer.  */
61
  if ((*end - *begin) >= *size) {
62
    kwsysSystem_ptrdiff_t length = *end - *begin;
63 64
    char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*));
    if (!newPointers) {
65
      return 0;
66 67 68
    }
    memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*));
    if (*begin != local) {
69
      free(*begin);
70
    }
71 72 73
    *begin = newPointers;
    *end = *begin + length;
    *size *= 2;
74
  }
75 76 77

  /* Allocate space for the argument string.  */
  **end = (char*)malloc((size_t)(*arg_end - *arg_begin));
78
  if (!**end) {
79
    return 0;
80
  }
81 82

  /* Store the argument in the command array.  */
83
  memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin));
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
  ++(*end);

  /* Reset the argument to be empty.  */
  *arg_end = *arg_begin;

  return 1;
}

#define KWSYSPE_LOCAL_BYTE_COUNT 1024
#define KWSYSPE_LOCAL_ARGS_COUNT 32
static char** kwsysSystem__ParseUnixCommand(const char* command, int flags)
{
  /* Create a buffer for argument pointers during parsing.  */
  char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT];
  int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT;
  char** pointer_begin = local_pointers;
  char** pointer_end = pointer_begin;

  /* Create a buffer for argument strings during parsing.  */
  char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT];
  int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT;
  char* buffer_begin = local_buffer;
  char* buffer_end = buffer_begin;

  /* Parse the command string.  Try to behave like a UNIX shell.  */
  char** newCommand = 0;
  const char* c = command;
  int in_argument = 0;
  int in_escape = 0;
  int in_single = 0;
  int in_double = 0;
  int failed = 0;
116 117
  for (; *c; ++c) {
    if (in_escape) {
118
      /* This character is escaped so do no special handling.  */
119
      if (!in_argument) {
120
        in_argument = 1;
121 122 123
      }
      if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end,
                                   &buffer_size, *c)) {
124 125 126
        failed = 1;
        break;
      }
127 128
      in_escape = 0;
    } else if (*c == '\\') {
129 130
      /* The next character should be escaped.  */
      in_escape = 1;
131
    } else if (*c == '\'' && !in_double) {
132
      /* Enter or exit single-quote state.  */
133
      if (in_single) {
134
        in_single = 0;
135
      } else {
136
        in_single = 1;
137
        if (!in_argument) {
138 139 140
          in_argument = 1;
        }
      }
141
    } else if (*c == '"' && !in_single) {
142
      /* Enter or exit double-quote state.  */
143
      if (in_double) {
144
        in_double = 0;
145
      } else {
146
        in_double = 1;
147
        if (!in_argument) {
148 149 150
          in_argument = 1;
        }
      }
151 152 153
    } else if (isspace((unsigned char)*c)) {
      if (in_argument) {
        if (in_single || in_double) {
154
          /* This space belongs to a quoted argument.  */
155 156
          if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin,
                                       &buffer_end, &buffer_size, *c)) {
157 158 159
            failed = 1;
            break;
          }
160
        } else {
161
          /* This argument has been terminated by whitespace.  */
162 163 164
          if (!kwsysSystem__AppendArgument(
                local_pointers, &pointer_begin, &pointer_end, &pointers_size,
                local_buffer, &buffer_begin, &buffer_end, &buffer_size)) {
165 166 167
            failed = 1;
            break;
          }
168
          in_argument = 0;
169 170
        }
      }
171
    } else {
172
      /* This character belong to an argument.  */
173
      if (!in_argument) {
174
        in_argument = 1;
175 176 177
      }
      if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end,
                                   &buffer_size, *c)) {
178 179 180 181
        failed = 1;
        break;
      }
    }
182
  }
183 184

  /* Finish the last argument.  */
185 186 187 188
  if (in_argument) {
    if (!kwsysSystem__AppendArgument(
          local_pointers, &pointer_begin, &pointer_end, &pointers_size,
          local_buffer, &buffer_begin, &buffer_end, &buffer_size)) {
189 190
      failed = 1;
    }
191
  }
192 193 194

  /* If we still have memory allocate space for the new command
     buffer.  */
195
  if (!failed) {
196
    kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
197 198
    newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*));
  }
199

200
  if (newCommand) {
201 202
    /* Copy the arguments into the new command buffer.  */
    kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
203
    memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n));
204
    newCommand[n] = 0;
205
  } else {
206
    /* Free arguments already allocated.  */
207
    while (pointer_end != pointer_begin) {
208 209
      free(*(--pointer_end));
    }
210
  }
211 212

  /* Free temporary buffers.  */
213
  if (pointer_begin != local_pointers) {
214
    free(pointer_begin);
215 216
  }
  if (buffer_begin != local_buffer) {
217
    free(buffer_begin);
218
  }
219 220 221 222 223 224 225 226 227 228 229

  /* The flags argument is currently unused.  */
  (void)flags;

  /* Return the final command buffer.  */
  return newCommand;
}

char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags)
{
  /* Validate the flags.  */
230
  if (flags != 0) {
231
    return 0;
232
  }
233 234 235 236

  /* Forward to our internal implementation.  */
  return kwsysSystem__ParseUnixCommand(command, flags);
}