[348] | 1 | /* $Id: append.c 3246 2018-12-25 21:02:04Z bird $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * kMk Builtin command - append text to file.
|
---|
[2015] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[2413] | 7 | * Copyright (c) 2005-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
|
---|
[348] | 8 | *
|
---|
| 9 | * This file is part of kBuild.
|
---|
| 10 | *
|
---|
| 11 | * kBuild is free software; you can redistribute it and/or modify
|
---|
| 12 | * it under the terms of the GNU General Public License as published by
|
---|
[2019] | 13 | * the Free Software Foundation; either version 3 of the License, or
|
---|
[348] | 14 | * (at your option) any later version.
|
---|
| 15 | *
|
---|
| 16 | * kBuild is distributed in the hope that it will be useful,
|
---|
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 19 | * GNU General Public License for more details.
|
---|
| 20 | *
|
---|
| 21 | * You should have received a copy of the GNU General Public License
|
---|
[2019] | 22 | * along with kBuild. If not, see <http://www.gnu.org/licenses/>
|
---|
[348] | 23 | *
|
---|
| 24 | */
|
---|
| 25 |
|
---|
[3192] | 26 | /*********************************************************************************************************************************
|
---|
| 27 | * Header Files *
|
---|
| 28 | *********************************************************************************************************************************/
|
---|
| 29 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[3140] | 30 | # include "makeint.h"
|
---|
[820] | 31 | # include "filedef.h"
|
---|
[769] | 32 | # include "variable.h"
|
---|
[2113] | 33 | #else
|
---|
| 34 | # include "config.h"
|
---|
[769] | 35 | #endif
|
---|
[2113] | 36 | #include <string.h>
|
---|
| 37 | #include <stdio.h>
|
---|
[3246] | 38 | #include <stdlib.h>
|
---|
[3171] | 39 | #include <fcntl.h>
|
---|
| 40 | #ifdef HAVE_UNISTD_H
|
---|
| 41 | # include <unistd.h>
|
---|
| 42 | #endif
|
---|
| 43 | #ifdef _MSC_VER
|
---|
| 44 | # include <io.h>
|
---|
| 45 | #endif
|
---|
[2121] | 46 | #ifdef HAVE_ALLOCA_H
|
---|
| 47 | # include <alloca.h>
|
---|
| 48 | #endif
|
---|
[3192] | 49 | #if !defined(KMK_BUILTIN_STANDALONE) && defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN)
|
---|
[3172] | 50 | # include "../w32/winchildren.h"
|
---|
| 51 | #endif
|
---|
[2113] | 52 | #include "err.h"
|
---|
| 53 | #include "kmkbuiltin.h"
|
---|
[348] | 54 |
|
---|
[767] | 55 |
|
---|
[3171] | 56 | /*********************************************************************************************************************************
|
---|
| 57 | * Defined Constants And Macros *
|
---|
| 58 | *********************************************************************************************************************************/
|
---|
| 59 | #define STR_TUPLE(a_sz) a_sz, (sizeof(a_sz) - 1)
|
---|
| 60 |
|
---|
| 61 | /** No-inherit open flag. */
|
---|
| 62 | #ifdef _O_NOINHERIT
|
---|
| 63 | # define MY_O_NOINHERIT _O_NOINHERIT
|
---|
| 64 | #elif defined(O_NOINHERIT)
|
---|
| 65 | # define MY_O_NOINHERIT O_NOINHERIT
|
---|
| 66 | #elif defined(O_CLOEXEC)
|
---|
| 67 | # define MY_O_NOINHERIT O_CLOEXEC
|
---|
| 68 | #else
|
---|
| 69 | # define MY_O_NOINHERIT 0
|
---|
| 70 | #endif
|
---|
| 71 |
|
---|
| 72 | /** Binary mode open flag. */
|
---|
| 73 | #ifdef _O_BINARY
|
---|
| 74 | # define MY_O_BINARY _O_BINARY
|
---|
| 75 | #elif defined(O_BINARY)
|
---|
| 76 | # define MY_O_BINARY O_BINARY
|
---|
| 77 | #else
|
---|
| 78 | # define MY_O_BINARY 0
|
---|
| 79 | #endif
|
---|
| 80 |
|
---|
| 81 |
|
---|
| 82 | /*********************************************************************************************************************************
|
---|
| 83 | * Structures and Typedefs *
|
---|
| 84 | *********************************************************************************************************************************/
|
---|
[348] | 85 | /**
|
---|
[3171] | 86 | * Append output buffer.
|
---|
| 87 | */
|
---|
| 88 | typedef struct KMKBUILTINAPPENDBUF
|
---|
| 89 | {
|
---|
| 90 | /** Buffer pointer. */
|
---|
| 91 | char *pszBuf;
|
---|
| 92 | /** The buffer allocation size. */
|
---|
| 93 | size_t cbBuf;
|
---|
| 94 | /** The current buffer offset. */
|
---|
| 95 | size_t offBuf;
|
---|
| 96 | /** Set if we ran out of memory. */
|
---|
| 97 | int fOutOfMemory;
|
---|
| 98 | } KMKBUILTINAPPENDBUF;
|
---|
| 99 |
|
---|
| 100 |
|
---|
| 101 | /**
|
---|
| 102 | * Appends a substring to the output buffer.
|
---|
| 103 | *
|
---|
| 104 | * @param pBuf The output buffer.
|
---|
| 105 | * @param pch The substring pointer.
|
---|
| 106 | * @param cch The substring length.
|
---|
| 107 | */
|
---|
| 108 | static void write_to_buf(KMKBUILTINAPPENDBUF *pBuf, const char *pch, size_t cch)
|
---|
| 109 | {
|
---|
| 110 | size_t const offCur = pBuf->offBuf;
|
---|
| 111 | size_t offNew = offCur + cch;
|
---|
| 112 |
|
---|
| 113 | if (offNew >= pBuf->cbBuf)
|
---|
| 114 | {
|
---|
| 115 | size_t cbNew = offNew + 1 + 256;
|
---|
| 116 | void *pvNew;
|
---|
| 117 | cbNew = (cbNew + 511) & ~(size_t)511;
|
---|
| 118 | pvNew = realloc(pBuf->pszBuf, cbNew);
|
---|
| 119 | if (pvNew)
|
---|
| 120 | pBuf->pszBuf = (char *)pvNew;
|
---|
| 121 | else
|
---|
| 122 | {
|
---|
| 123 | free(pBuf->pszBuf);
|
---|
| 124 | pBuf->pszBuf = NULL;
|
---|
| 125 | pBuf->cbBuf = 0;
|
---|
[3177] | 126 | pBuf->offBuf = offNew;
|
---|
[3171] | 127 | pBuf->fOutOfMemory = 1;
|
---|
| 128 | return;
|
---|
| 129 | }
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | memcpy(&pBuf->pszBuf[offCur], pch, cch);
|
---|
| 133 | pBuf->pszBuf[offNew] = '\0';
|
---|
| 134 | pBuf->offBuf = offNew;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | /**
|
---|
| 138 | * Adds a string to the output buffer.
|
---|
| 139 | *
|
---|
| 140 | * @param pBuf The output buffer.
|
---|
| 141 | * @param psz The string.
|
---|
| 142 | */
|
---|
| 143 | static void string_to_buf(KMKBUILTINAPPENDBUF *pBuf, const char *psz)
|
---|
| 144 | {
|
---|
| 145 | write_to_buf(pBuf, psz, strlen(psz));
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 |
|
---|
| 149 | /**
|
---|
[767] | 150 | * Prints the usage and return 1.
|
---|
| 151 | */
|
---|
[3171] | 152 | static int kmk_builtin_append_usage(const char *arg0, FILE *pf)
|
---|
[767] | 153 | {
|
---|
[1183] | 154 | fprintf(pf,
|
---|
[2015] | 155 | "usage: %s [-dcnNtv] file [string ...]\n"
|
---|
[1183] | 156 | " or: %s --version\n"
|
---|
[1695] | 157 | " or: %s --help\n"
|
---|
| 158 | "\n"
|
---|
| 159 | "Options:\n"
|
---|
| 160 | " -d Enclose the output in define ... endef, taking the name from\n"
|
---|
| 161 | " the first argument following the file name.\n"
|
---|
| 162 | " -c Output the command for specified target(s). [builtin only]\n"
|
---|
[3134] | 163 | " -i look for --insert-command=trg and --insert-variable=var. [builtin only]\n"
|
---|
[2016] | 164 | " -n Insert a newline between the strings.\n"
|
---|
| 165 | " -N Suppress the trailing newline.\n"
|
---|
[1695] | 166 | " -t Truncate the file instead of appending\n"
|
---|
| 167 | " -v Output the value(s) for specified variable(s). [builtin only]\n"
|
---|
| 168 | ,
|
---|
[3171] | 169 | arg0, arg0, arg0);
|
---|
[767] | 170 | return 1;
|
---|
| 171 | }
|
---|
| 172 |
|
---|
| 173 | /**
|
---|
[348] | 174 | * Appends text to a textfile, creating the textfile if necessary.
|
---|
| 175 | */
|
---|
[3192] | 176 | int kmk_builtin_append(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned)
|
---|
[348] | 177 | {
|
---|
[3172] | 178 | #if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
|
---|
| 179 | static const char s_szNewLine[] = "\r\n";
|
---|
| 180 | #else
|
---|
| 181 | static const char s_szNewLine[] = "\n";
|
---|
| 182 | #endif
|
---|
| 183 | KMKBUILTINAPPENDBUF OutBuf = { NULL, 0, 0, 0 };
|
---|
[3171] | 184 | const char *pszFilename;
|
---|
| 185 | int rc = 88;
|
---|
[348] | 186 | int i;
|
---|
[767] | 187 | int fFirst;
|
---|
[2016] | 188 | int fNewline = 0;
|
---|
| 189 | int fNoTrailingNewline = 0;
|
---|
[1695] | 190 | int fTruncate = 0;
|
---|
| 191 | int fDefine = 0;
|
---|
[769] | 192 | int fVariables = 0;
|
---|
[1440] | 193 | int fCommands = 0;
|
---|
[3192] | 194 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[3134] | 195 | int fLookForInserts = 0;
|
---|
[3192] | 196 | #else
|
---|
| 197 | (void)pChild; (void)pPidSpawned;
|
---|
[3141] | 198 | #endif
|
---|
[348] | 199 |
|
---|
| 200 | /*
|
---|
[767] | 201 | * Parse options.
|
---|
| 202 | */
|
---|
| 203 | i = 1;
|
---|
| 204 | while (i < argc
|
---|
| 205 | && argv[i][0] == '-'
|
---|
| 206 | && argv[i][1] != '\0' /* '-' is a file */
|
---|
[3134] | 207 | && strchr("-cdinNtv", argv[i][1]) /* valid option char */
|
---|
[767] | 208 | )
|
---|
| 209 | {
|
---|
| 210 | char *psz = &argv[i][1];
|
---|
[1183] | 211 | if (*psz != '-')
|
---|
[767] | 212 | {
|
---|
[1183] | 213 | do
|
---|
[767] | 214 | {
|
---|
[1183] | 215 | switch (*psz)
|
---|
| 216 | {
|
---|
[1440] | 217 | case 'c':
|
---|
[1695] | 218 | if (fVariables)
|
---|
| 219 | {
|
---|
[3192] | 220 | errx(pCtx, 1, "Option '-c' clashes with '-v'.");
|
---|
[3171] | 221 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[1695] | 222 | }
|
---|
[3192] | 223 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[1440] | 224 | fCommands = 1;
|
---|
| 225 | break;
|
---|
| 226 | #else
|
---|
[3192] | 227 | errx(pCtx, 1, "Option '-c' isn't supported in external mode.");
|
---|
[3171] | 228 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[1440] | 229 | #endif
|
---|
[1695] | 230 | case 'd':
|
---|
| 231 | if (fVariables)
|
---|
| 232 | {
|
---|
[3192] | 233 | errx(pCtx, 1, "Option '-d' must come before '-v'!");
|
---|
[3171] | 234 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[1695] | 235 | }
|
---|
| 236 | fDefine = 1;
|
---|
| 237 | break;
|
---|
[3134] | 238 | case 'i':
|
---|
| 239 | if (fVariables || fCommands)
|
---|
| 240 | {
|
---|
[3192] | 241 | errx(pCtx, 1, fVariables ? "Option '-i' clashes with '-v'." : "Option '-i' clashes with '-c'.");
|
---|
[3171] | 242 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[3134] | 243 | }
|
---|
[3192] | 244 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[3134] | 245 | fLookForInserts = 1;
|
---|
| 246 | break;
|
---|
| 247 | #else
|
---|
[3192] | 248 | errx(pCtx, 1, "Option '-C' isn't supported in external mode.");
|
---|
[3171] | 249 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[3134] | 250 | #endif
|
---|
[1183] | 251 | case 'n':
|
---|
[2016] | 252 | fNewline = 1;
|
---|
[1183] | 253 | break;
|
---|
[2015] | 254 | case 'N':
|
---|
[2016] | 255 | fNoTrailingNewline = 1;
|
---|
[2015] | 256 | break;
|
---|
[1695] | 257 | case 't':
|
---|
| 258 | fTruncate = 1;
|
---|
| 259 | break;
|
---|
[1183] | 260 | case 'v':
|
---|
[1695] | 261 | if (fCommands)
|
---|
| 262 | {
|
---|
[3192] | 263 | errx(pCtx, 1, "Option '-v' clashes with '-c'.");
|
---|
[3171] | 264 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[1695] | 265 | }
|
---|
[3192] | 266 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[1183] | 267 | fVariables = 1;
|
---|
| 268 | break;
|
---|
[769] | 269 | #else
|
---|
[3192] | 270 | errx(pCtx, 1, "Option '-v' isn't supported in external mode.");
|
---|
[3171] | 271 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[769] | 272 | #endif
|
---|
[1183] | 273 | default:
|
---|
[3192] | 274 | errx(pCtx, 1, "Invalid option '%c'! (%s)", *psz, argv[i]);
|
---|
[3171] | 275 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[1183] | 276 | }
|
---|
| 277 | } while (*++psz);
|
---|
| 278 | }
|
---|
| 279 | else if (!strcmp(psz, "-help"))
|
---|
| 280 | {
|
---|
[3171] | 281 | kmk_builtin_append_usage(argv[0], stdout);
|
---|
[1183] | 282 | return 0;
|
---|
| 283 | }
|
---|
| 284 | else if (!strcmp(psz, "-version"))
|
---|
| 285 | return kbuild_version(argv[0]);
|
---|
| 286 | else
|
---|
| 287 | break;
|
---|
[767] | 288 | i++;
|
---|
| 289 | }
|
---|
| 290 |
|
---|
[3171] | 291 | /*
|
---|
| 292 | * Take down the filename.
|
---|
| 293 | */
|
---|
| 294 | if (i + fDefine < argc)
|
---|
| 295 | pszFilename = argv[i++];
|
---|
| 296 | else
|
---|
[1695] | 297 | {
|
---|
| 298 | if (i <= argc)
|
---|
[3192] | 299 | errx(pCtx, 1, "missing filename!");
|
---|
[1695] | 300 | else
|
---|
[3192] | 301 | errx(pCtx, 1, "missing define name!");
|
---|
[3171] | 302 | return kmk_builtin_append_usage(argv[0], stderr);
|
---|
[1695] | 303 | }
|
---|
| 304 |
|
---|
[3171] | 305 | /* Start of no-return zone! */
|
---|
[348] | 306 |
|
---|
| 307 | /*
|
---|
[1695] | 308 | * Start define?
|
---|
| 309 | */
|
---|
| 310 | if (fDefine)
|
---|
| 311 | {
|
---|
[3171] | 312 | write_to_buf(&OutBuf, STR_TUPLE("define "));
|
---|
| 313 | string_to_buf(&OutBuf, argv[i]);
|
---|
| 314 | write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
|
---|
[1695] | 315 | i++;
|
---|
| 316 | }
|
---|
| 317 |
|
---|
| 318 | /*
|
---|
[348] | 319 | * Append the argument strings to the file
|
---|
| 320 | */
|
---|
[767] | 321 | fFirst = 1;
|
---|
[3171] | 322 | for (; i < argc; i++)
|
---|
[348] | 323 | {
|
---|
| 324 | const char *psz = argv[i];
|
---|
| 325 | size_t cch = strlen(psz);
|
---|
[767] | 326 | if (!fFirst)
|
---|
[3171] | 327 | {
|
---|
| 328 | if (fNewline)
|
---|
| 329 | write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
|
---|
| 330 | else
|
---|
| 331 | write_to_buf(&OutBuf, STR_TUPLE(" "));
|
---|
| 332 | }
|
---|
[3192] | 333 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[1440] | 334 | if (fCommands)
|
---|
[769] | 335 | {
|
---|
[1440] | 336 | char *pszOldBuf;
|
---|
| 337 | unsigned cchOldBuf;
|
---|
| 338 | char *pchEnd;
|
---|
| 339 |
|
---|
| 340 | install_variable_buffer(&pszOldBuf, &cchOldBuf);
|
---|
| 341 |
|
---|
| 342 | pchEnd = func_commands(variable_buffer, &argv[i], "commands");
|
---|
[3171] | 343 | write_to_buf(&OutBuf, variable_buffer, pchEnd - variable_buffer);
|
---|
[1440] | 344 |
|
---|
| 345 | restore_variable_buffer(pszOldBuf, cchOldBuf);
|
---|
| 346 | }
|
---|
| 347 | else if (fVariables)
|
---|
| 348 | {
|
---|
[769] | 349 | struct variable *pVar = lookup_variable(psz, cch);
|
---|
| 350 | if (!pVar)
|
---|
| 351 | continue;
|
---|
[2771] | 352 | if ( !pVar->recursive
|
---|
| 353 | || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
|
---|
[3171] | 354 | write_to_buf(&OutBuf, pVar->value, pVar->value_length);
|
---|
[2771] | 355 | else
|
---|
[769] | 356 | {
|
---|
| 357 | char *pszExpanded = allocated_variable_expand(pVar->value);
|
---|
[3171] | 358 | string_to_buf(&OutBuf, pszExpanded);
|
---|
[769] | 359 | free(pszExpanded);
|
---|
| 360 | }
|
---|
| 361 | }
|
---|
[3134] | 362 | else if (fLookForInserts && strncmp(psz, "--insert-command=", 17) == 0)
|
---|
| 363 | {
|
---|
| 364 | char *pszOldBuf;
|
---|
| 365 | unsigned cchOldBuf;
|
---|
| 366 | char *pchEnd;
|
---|
| 367 |
|
---|
| 368 | install_variable_buffer(&pszOldBuf, &cchOldBuf);
|
---|
| 369 |
|
---|
| 370 | psz += 17;
|
---|
| 371 | pchEnd = func_commands(variable_buffer, (char **)&psz, "commands");
|
---|
[3171] | 372 | write_to_buf(&OutBuf, variable_buffer, pchEnd - variable_buffer);
|
---|
[3134] | 373 |
|
---|
| 374 | restore_variable_buffer(pszOldBuf, cchOldBuf);
|
---|
| 375 | }
|
---|
| 376 | else if (fLookForInserts && strncmp(psz, "--insert-variable=", 18) == 0)
|
---|
| 377 | {
|
---|
| 378 | struct variable *pVar = lookup_variable(psz + 18, cch);
|
---|
| 379 | if (!pVar)
|
---|
| 380 | continue;
|
---|
| 381 | if ( !pVar->recursive
|
---|
| 382 | || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
|
---|
[3171] | 383 | write_to_buf(&OutBuf, pVar->value, pVar->value_length);
|
---|
[3134] | 384 | else
|
---|
| 385 | {
|
---|
| 386 | char *pszExpanded = allocated_variable_expand(pVar->value);
|
---|
[3171] | 387 | string_to_buf(&OutBuf, pszExpanded);
|
---|
[3134] | 388 | free(pszExpanded);
|
---|
| 389 | }
|
---|
| 390 | }
|
---|
[767] | 391 | else
|
---|
[769] | 392 | #endif
|
---|
[3171] | 393 | write_to_buf(&OutBuf, psz, cch);
|
---|
[769] | 394 | fFirst = 0;
|
---|
[348] | 395 | }
|
---|
| 396 |
|
---|
[2015] | 397 | /*
|
---|
| 398 | * End the define?
|
---|
[348] | 399 | */
|
---|
[2015] | 400 | if (fDefine)
|
---|
| 401 | {
|
---|
| 402 | if (fFirst)
|
---|
[3171] | 403 | write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
|
---|
| 404 | write_to_buf(&OutBuf, STR_TUPLE("endef"));
|
---|
[2015] | 405 | }
|
---|
| 406 |
|
---|
| 407 | /*
|
---|
[3171] | 408 | * Add final newline (unless supressed) and check for errors.
|
---|
[2015] | 409 | */
|
---|
[3171] | 410 | if (!fNoTrailingNewline)
|
---|
| 411 | write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
|
---|
| 412 |
|
---|
| 413 | /*
|
---|
| 414 | * Write the buffer (unless we ran out of heap already).
|
---|
| 415 | */
|
---|
[3192] | 416 | #if !defined(KMK_BUILTIN_STANDALONE) && defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN)
|
---|
[3171] | 417 | if (!OutBuf.fOutOfMemory)
|
---|
[348] | 418 | {
|
---|
[3172] | 419 | rc = MkWinChildCreateAppend(pszFilename, &OutBuf.pszBuf, OutBuf.offBuf, fTruncate, pChild, pPidSpawned);
|
---|
| 420 | if (rc != 0)
|
---|
[3192] | 421 | rc = errx(pCtx, rc, "MkWinChildCreateAppend failed: %u", rc);
|
---|
[3172] | 422 | if (OutBuf.pszBuf)
|
---|
| 423 | free(OutBuf.pszBuf);
|
---|
| 424 | }
|
---|
| 425 | else
|
---|
| 426 | #endif
|
---|
| 427 | if (!OutBuf.fOutOfMemory)
|
---|
| 428 | {
|
---|
[3171] | 429 | int fd = open(pszFilename,
|
---|
| 430 | fTruncate ? O_WRONLY | O_TRUNC | O_CREAT | MY_O_NOINHERIT | MY_O_BINARY
|
---|
| 431 | : O_WRONLY | O_APPEND | O_CREAT | MY_O_NOINHERIT | MY_O_BINARY,
|
---|
| 432 | 0666);
|
---|
| 433 | if (fd >= 0)
|
---|
| 434 | {
|
---|
| 435 | ssize_t cbWritten = write(fd, OutBuf.pszBuf, OutBuf.offBuf);
|
---|
| 436 | if (cbWritten == (ssize_t)OutBuf.offBuf)
|
---|
| 437 | rc = 0;
|
---|
| 438 | else
|
---|
[3192] | 439 | rc = err(pCtx, 1, "error writing %lu bytes to '%s'", (unsigned long)OutBuf.offBuf, pszFilename);
|
---|
[3171] | 440 | if (close(fd) < 0)
|
---|
[3192] | 441 | rc = err(pCtx, 1, "error closing '%s'", pszFilename);
|
---|
[3171] | 442 | }
|
---|
| 443 | else
|
---|
[3192] | 444 | rc = err(pCtx, 1, "failed to open '%s'", pszFilename);
|
---|
[3171] | 445 | free(OutBuf.pszBuf);
|
---|
[348] | 446 | }
|
---|
[3171] | 447 | else
|
---|
[3192] | 448 | rc = errx(pCtx, 1, "out of memory for output buffer! (%u needed)", OutBuf.offBuf + 1);
|
---|
[3171] | 449 | return rc;
|
---|
[348] | 450 | }
|
---|
| 451 |
|
---|
[3192] | 452 | #ifdef KMK_BUILTIN_STANDALONE
|
---|
| 453 | int main(int argc, char **argv, char **envp)
|
---|
| 454 | {
|
---|
| 455 | KMKBUILTINCTX Ctx = { "kmk_append", NULL };
|
---|
| 456 | return kmk_builtin_append(argc, argv, envp, &Ctx, NULL, NULL);
|
---|
| 457 | }
|
---|
| 458 | #endif
|
---|
| 459 |
|
---|