Changeset 3171 for trunk/src/kmk/kmkbuiltin
- Timestamp:
- Mar 21, 2018, 2:26:36 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmkbuiltin/append.c
r3159 r3171 36 36 #include <string.h> 37 37 #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 38 45 #ifdef HAVE_ALLOCA_H 39 46 # include <alloca.h> … … 43 50 44 51 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 */ 84 typedef 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 */ 104 static 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 */ 138 static void string_to_buf(KMKBUILTINAPPENDBUF *pBuf, const char *psz) 139 { 140 write_to_buf(pBuf, psz, strlen(psz)); 141 } 142 143 45 144 /** 46 145 * Prints the usage and return 1. 47 146 */ 48 static int usage(FILE *pf)147 static int kmk_builtin_append_usage(const char *arg0, FILE *pf) 49 148 { 50 149 fprintf(pf, … … 63 162 " -v Output the value(s) for specified variable(s). [builtin only]\n" 64 163 , 65 g_progname, g_progname, g_progname);164 arg0, arg0, arg0); 66 165 return 1; 67 166 } 68 167 69 70 168 /** 71 169 * Appends text to a textfile, creating the textfile if necessary. … … 73 171 int kmk_builtin_append(int argc, char **argv, char **envp) 74 172 { 173 const char *pszFilename; 174 int rc = 88; 75 175 int i; 76 176 int fFirst; 77 int iFile;78 FILE *pFile;79 177 int fNewline = 0; 80 178 int fNoTrailingNewline = 0; … … 86 184 int fLookForInserts = 0; 87 185 #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 }; 88 192 89 193 g_progname = argv[0]; … … 110 214 { 111 215 errx(1, "Option '-c' clashes with '-v'."); 112 return usage(stderr);216 return kmk_builtin_append_usage(argv[0], stderr); 113 217 } 114 218 #ifndef kmk_builtin_append … … 117 221 #else 118 222 errx(1, "Option '-c' isn't supported in external mode."); 119 return usage(stderr);223 return kmk_builtin_append_usage(argv[0], stderr); 120 224 #endif 121 225 case 'd': … … 123 227 { 124 228 errx(1, "Option '-d' must come before '-v'!"); 125 return usage(stderr);229 return kmk_builtin_append_usage(argv[0], stderr); 126 230 } 127 231 fDefine = 1; … … 131 235 { 132 236 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); 134 238 } 135 239 #ifndef kmk_builtin_append … … 138 242 #else 139 243 errx(1, "Option '-C' isn't supported in external mode."); 140 return usage(stderr);244 return kmk_builtin_append_usage(argv[0], stderr); 141 245 #endif 142 246 case 'n': … … 153 257 { 154 258 errx(1, "Option '-v' clashes with '-c'."); 155 return usage(stderr);259 return kmk_builtin_append_usage(argv[0], stderr); 156 260 } 157 261 #ifndef kmk_builtin_append … … 160 264 #else 161 265 errx(1, "Option '-v' isn't supported in external mode."); 162 return usage(stderr);266 return kmk_builtin_append_usage(argv[0], stderr); 163 267 #endif 164 268 default: 165 269 errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]); 166 return usage(stderr);270 return kmk_builtin_append_usage(argv[0], stderr); 167 271 } 168 272 } while (*++psz); … … 170 274 else if (!strcmp(psz, "-help")) 171 275 { 172 usage(stdout);276 kmk_builtin_append_usage(argv[0], stdout); 173 277 return 0; 174 278 } … … 180 284 } 181 285 182 if (i + fDefine >= argc) 286 /* 287 * Take down the filename. 288 */ 289 if (i + fDefine < argc) 290 pszFilename = argv[i++]; 291 else 183 292 { 184 293 if (i <= argc) … … 186 295 else 187 296 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! */ 200 301 201 302 /* … … 204 305 if (fDefine) 205 306 { 307 write_to_buf(&OutBuf, STR_TUPLE("define ")); 308 string_to_buf(&OutBuf, argv[i]); 309 write_to_buf(&OutBuf, STR_TUPLE(s_szNewLine)); 206 310 i++; 207 fprintf(pFile, "define %s\n", argv[i]);208 311 } 209 312 … … 212 315 */ 213 316 fFirst = 1; 214 for ( i++; i < argc; i++)317 for (; i < argc; i++) 215 318 { 216 319 const char *psz = argv[i]; 217 320 size_t cch = strlen(psz); 218 321 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 } 220 328 #ifndef kmk_builtin_append 221 329 if (fCommands) … … 228 336 229 337 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); 231 339 232 340 restore_variable_buffer(pszOldBuf, cchOldBuf); … … 239 347 if ( !pVar->recursive 240 348 || 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); 242 350 else 243 351 { 244 352 char *pszExpanded = allocated_variable_expand(pVar->value); 245 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);353 string_to_buf(&OutBuf, pszExpanded); 246 354 free(pszExpanded); 247 355 } … … 257 365 psz += 17; 258 366 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); 260 368 261 369 restore_variable_buffer(pszOldBuf, cchOldBuf); … … 268 376 if ( !pVar->recursive 269 377 || 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); 271 379 else 272 380 { 273 381 char *pszExpanded = allocated_variable_expand(pVar->value); 274 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);382 string_to_buf(&OutBuf, pszExpanded); 275 383 free(pszExpanded); 276 384 } … … 278 386 else 279 387 #endif 280 fwrite(psz, 1, cch, pFile);388 write_to_buf(&OutBuf, psz, cch); 281 389 fFirst = 0; 282 390 } … … 288 396 { 289 397 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 } 291 427 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; 308 434 } 309 435
Note:
See TracChangeset
for help on using the changeset viewer.