Changeset 3171 for trunk/src


Ignore:
Timestamp:
Mar 21, 2018, 2:26:36 PM (7 years ago)
Author:
bird
Message:

kmk_append: do own buffering so we can outsource the writing on windows where file system access sucks.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kmkbuiltin/append.c

    r3159 r3171  
    3636#include <string.h>
    3737#include <stdio.h>
     38#include <fcntl.h>
     39#ifdef HAVE_UNISTD_H
     40# include <unistd.h>
     41#endif
     42#ifdef _MSC_VER
     43# include <io.h>
     44#endif
    3845#ifdef HAVE_ALLOCA_H
    3946# include <alloca.h>
     
    4350
    4451
     52/*********************************************************************************************************************************
     53*   Defined Constants And Macros                                                                                                 *
     54*********************************************************************************************************************************/
     55#define STR_TUPLE(a_sz)     a_sz, (sizeof(a_sz) - 1)
     56
     57/** No-inherit open flag.   */
     58#ifdef _O_NOINHERIT
     59# define MY_O_NOINHERIT     _O_NOINHERIT
     60#elif defined(O_NOINHERIT)
     61# define MY_O_NOINHERIT     O_NOINHERIT
     62#elif defined(O_CLOEXEC)
     63# define MY_O_NOINHERIT     O_CLOEXEC
     64#else
     65# define MY_O_NOINHERIT     0
     66#endif
     67
     68/** Binary mode open flag. */
     69#ifdef _O_BINARY
     70# define MY_O_BINARY        _O_BINARY
     71#elif defined(O_BINARY)
     72# define MY_O_BINARY        O_BINARY
     73#else
     74# define MY_O_BINARY        0
     75#endif
     76
     77
     78/*********************************************************************************************************************************
     79*   Structures and Typedefs                                                                                                      *
     80*********************************************************************************************************************************/
     81/**
     82 * Append output buffer.
     83 */
     84typedef struct KMKBUILTINAPPENDBUF
     85{
     86    /** Buffer pointer. */
     87    char   *pszBuf;
     88    /** The buffer allocation size. */
     89    size_t  cbBuf;
     90    /** The current buffer offset. */
     91    size_t  offBuf;
     92    /** Set if we ran out of memory. */
     93    int     fOutOfMemory;
     94} KMKBUILTINAPPENDBUF;
     95
     96
     97/**
     98 * Appends a substring to the output buffer.
     99 *
     100 * @param   pBuf        The output buffer.
     101 * @param   pch         The substring pointer.
     102 * @param   cch         The substring length.
     103 */
     104static void write_to_buf(KMKBUILTINAPPENDBUF *pBuf, const char *pch, size_t cch)
     105{
     106    size_t const offCur = pBuf->offBuf;
     107    size_t       offNew = offCur + cch;
     108
     109    if (offNew >= pBuf->cbBuf)
     110    {
     111        size_t cbNew = offNew + 1 + 256;
     112        void  *pvNew;
     113        cbNew = (cbNew + 511) & ~(size_t)511;
     114        pvNew = realloc(pBuf->pszBuf, cbNew);
     115        if (pvNew)
     116            pBuf->pszBuf = (char *)pvNew;
     117        else
     118        {
     119            free(pBuf->pszBuf);
     120            pBuf->pszBuf = NULL;
     121            pBuf->cbBuf  = 0;
     122            pBuf->fOutOfMemory = 1;
     123            return;
     124        }
     125    }
     126
     127    memcpy(&pBuf->pszBuf[offCur], pch, cch);
     128    pBuf->pszBuf[offNew] = '\0';
     129    pBuf->offBuf = offNew;
     130}
     131
     132/**
     133 * Adds a string to the output buffer.
     134 *
     135 * @param   pBuf        The output buffer.
     136 * @param   psz         The string.
     137 */
     138static void string_to_buf(KMKBUILTINAPPENDBUF *pBuf, const char *psz)
     139{
     140    write_to_buf(pBuf, psz, strlen(psz));
     141}
     142
     143
    45144/**
    46145 * Prints the usage and return 1.
    47146 */
    48 static int usage(FILE *pf)
     147static int kmk_builtin_append_usage(const char *arg0, FILE *pf)
    49148{
    50149    fprintf(pf,
     
    63162            "  -v  Output the value(s) for specified variable(s). [builtin only]\n"
    64163            ,
    65             g_progname, g_progname, g_progname);
     164            arg0, arg0, arg0);
    66165    return 1;
    67166}
    68167
    69 
    70168/**
    71169 * Appends text to a textfile, creating the textfile if necessary.
     
    73171int kmk_builtin_append(int argc, char **argv, char **envp)
    74172{
     173    const char *pszFilename;
     174    int rc = 88;
    75175    int i;
    76176    int fFirst;
    77     int iFile;
    78     FILE *pFile;
    79177    int fNewline = 0;
    80178    int fNoTrailingNewline = 0;
     
    86184    int fLookForInserts = 0;
    87185#endif
     186#if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
     187    static const char s_szNewLine[] = "\r\n";
     188#else
     189    static const char s_szNewLine[] = "\n";
     190#endif
     191    KMKBUILTINAPPENDBUF OutBuf = { NULL, 0, 0, 0 };
    88192
    89193    g_progname = argv[0];
     
    110214                        {
    111215                            errx(1, "Option '-c' clashes with '-v'.");
    112                             return usage(stderr);
     216                            return kmk_builtin_append_usage(argv[0], stderr);
    113217                        }
    114218#ifndef kmk_builtin_append
     
    117221#else
    118222                        errx(1, "Option '-c' isn't supported in external mode.");
    119                         return usage(stderr);
     223                        return kmk_builtin_append_usage(argv[0], stderr);
    120224#endif
    121225                    case 'd':
     
    123227                        {
    124228                            errx(1, "Option '-d' must come before '-v'!");
    125                             return usage(stderr);
     229                            return kmk_builtin_append_usage(argv[0], stderr);
    126230                        }
    127231                        fDefine = 1;
     
    131235                        {
    132236                            errx(1, fVariables ? "Option '-i' clashes with '-v'." : "Option '-i' clashes with '-c'.");
    133                             return usage(stderr);
     237                            return kmk_builtin_append_usage(argv[0], stderr);
    134238                        }
    135239#ifndef kmk_builtin_append
     
    138242#else
    139243                        errx(1, "Option '-C' isn't supported in external mode.");
    140                         return usage(stderr);
     244                        return kmk_builtin_append_usage(argv[0], stderr);
    141245#endif
    142246                    case 'n':
     
    153257                        {
    154258                            errx(1, "Option '-v' clashes with '-c'.");
    155                             return usage(stderr);
     259                            return kmk_builtin_append_usage(argv[0], stderr);
    156260                        }
    157261#ifndef kmk_builtin_append
     
    160264#else
    161265                        errx(1, "Option '-v' isn't supported in external mode.");
    162                         return usage(stderr);
     266                        return kmk_builtin_append_usage(argv[0], stderr);
    163267#endif
    164268                    default:
    165269                        errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]);
    166                         return usage(stderr);
     270                        return kmk_builtin_append_usage(argv[0], stderr);
    167271                }
    168272            } while (*++psz);
     
    170274        else if (!strcmp(psz, "-help"))
    171275        {
    172             usage(stdout);
     276            kmk_builtin_append_usage(argv[0], stdout);
    173277            return 0;
    174278        }
     
    180284    }
    181285
    182     if (i + fDefine >= argc)
     286    /*
     287     * Take down the filename.
     288     */
     289    if (i + fDefine < argc)
     290        pszFilename = argv[i++];
     291    else
    183292    {
    184293        if (i <= argc)
     
    186295        else
    187296            errx(1, "missing define name!");
    188         return usage(stderr);
    189     }
    190 
    191     /*
    192      * Open the output file, preferrably with close-on-exec.
    193      */
    194     iFile = i;
    195     pFile = fopen(argv[i],
    196                   fTruncate ? "w" KMK_FOPEN_NO_INHERIT_MODE
    197                             : "a" KMK_FOPEN_NO_INHERIT_MODE);
    198     if (!pFile)
    199         return err(1, "failed to open '%s'", argv[i]);
     297        return kmk_builtin_append_usage(argv[0], stderr);
     298    }
     299
     300    /* Start of no-return zone! */
    200301
    201302    /*
     
    204305    if (fDefine)
    205306    {
     307        write_to_buf(&OutBuf, STR_TUPLE("define "));
     308        string_to_buf(&OutBuf, argv[i]);
     309        write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
    206310        i++;
    207         fprintf(pFile, "define %s\n", argv[i]);
    208311    }
    209312
     
    212315     */
    213316    fFirst = 1;
    214     for (i++; i < argc; i++)
     317    for (; i < argc; i++)
    215318    {
    216319        const char *psz = argv[i];
    217320        size_t cch = strlen(psz);
    218321        if (!fFirst)
    219             fputc(fNewline ? '\n' : ' ', pFile);
     322        {
     323            if (fNewline)
     324                write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
     325            else
     326                write_to_buf(&OutBuf, STR_TUPLE(" "));
     327        }
    220328#ifndef kmk_builtin_append
    221329        if (fCommands)
     
    228336
    229337            pchEnd = func_commands(variable_buffer, &argv[i], "commands");
    230             fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
     338            write_to_buf(&OutBuf, variable_buffer, pchEnd - variable_buffer);
    231339
    232340            restore_variable_buffer(pszOldBuf, cchOldBuf);
     
    239347            if (   !pVar->recursive
    240348                || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
    241                 fwrite(pVar->value, 1, pVar->value_length, pFile);
     349                write_to_buf(&OutBuf, pVar->value, pVar->value_length);
    242350            else
    243351            {
    244352                char *pszExpanded = allocated_variable_expand(pVar->value);
    245                 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
     353                string_to_buf(&OutBuf, pszExpanded);
    246354                free(pszExpanded);
    247355            }
     
    257365            psz += 17;
    258366            pchEnd = func_commands(variable_buffer, (char **)&psz, "commands");
    259             fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
     367            write_to_buf(&OutBuf, variable_buffer, pchEnd - variable_buffer);
    260368
    261369            restore_variable_buffer(pszOldBuf, cchOldBuf);
     
    268376            if (   !pVar->recursive
    269377                || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
    270                 fwrite(pVar->value, 1, pVar->value_length, pFile);
     378                write_to_buf(&OutBuf, pVar->value, pVar->value_length);
    271379            else
    272380            {
    273381                char *pszExpanded = allocated_variable_expand(pVar->value);
    274                 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
     382                string_to_buf(&OutBuf, pszExpanded);
    275383                free(pszExpanded);
    276384            }
     
    278386        else
    279387#endif
    280             fwrite(psz, 1, cch, pFile);
     388            write_to_buf(&OutBuf, psz, cch);
    281389        fFirst = 0;
    282390    }
     
    288396    {
    289397        if (fFirst)
    290             fwrite("\nendef", 1, sizeof("\nendef") - 1, pFile);
     398            write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
     399        write_to_buf(&OutBuf, STR_TUPLE("endef"));
     400    }
     401
     402    /*
     403     * Add final newline (unless supressed) and check for errors.
     404     */
     405    if (!fNoTrailingNewline)
     406        write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine));
     407
     408    /*
     409     * Write the buffer (unless we ran out of heap already).
     410     */
     411    if (!OutBuf.fOutOfMemory)
     412    {
     413        int fd = open(pszFilename,
     414                      fTruncate ? O_WRONLY | O_TRUNC  | O_CREAT | MY_O_NOINHERIT | MY_O_BINARY
     415                                : O_WRONLY | O_APPEND | O_CREAT | MY_O_NOINHERIT | MY_O_BINARY,
     416                      0666);
     417        if (fd >= 0)
     418        {
     419            ssize_t cbWritten = write(fd, OutBuf.pszBuf, OutBuf.offBuf);
     420            if (cbWritten == (ssize_t)OutBuf.offBuf)
     421                rc = 0;
     422            else
     423                rc = err(1, "error writing %lu bytes to '%s'", (unsigned long)OutBuf.offBuf, pszFilename);
     424            if (close(fd) < 0)
     425                rc = err(1, "error closing '%s'", pszFilename);
     426        }
    291427        else
    292             fwrite("endef", 1, sizeof("endef") - 1, pFile);
    293     }
    294 
    295     /*
    296      * Add the final newline (unless supressed) and close the file.
    297      */
    298     if (    (   !fNoTrailingNewline
    299              && fputc('\n', pFile) == EOF)
    300         ||  ferror(pFile))
    301     {
    302         fclose(pFile);
    303         return errx(1, "error writing to '%s'!", argv[iFile]);
    304     }
    305     if (fclose(pFile))
    306         return err(1, "failed to fclose '%s'!", argv[iFile]);
    307     return 0;
     428            rc = err(1, "failed to open '%s'", pszFilename);
     429        free(OutBuf.pszBuf);
     430    }
     431    else
     432        rc = errx(1, "out of memory!");
     433    return rc;
    308434}
    309435
Note: See TracChangeset for help on using the changeset viewer.