MCPcopy Create free account
hub / github.com/AutoHotkey/AutoHotkey / PerformLoopParse

Method PerformLoopParse

source/script.cpp:11359–11457  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

11357
11358
11359ResultType Line::PerformLoopParse(ResultToken *aResultToken, Line *&aJumpToLine, Line *aUntil)
11360{
11361 if (!*ARG1) // Since the input variable's contents are blank, the loop will execute zero times.
11362 return CONDITION_FALSE;
11363
11364 // The following will be used to hold the parsed items. It needs to have its own storage because
11365 // even though ARG1 might always be a writable memory area, we can't rely upon it being
11366 // persistent because it might reside in the deref buffer, in which case the other commands
11367 // in the loop's body would probably overwrite it. Even if the ARG1's contents aren't in
11368 // the deref buffer, we still can't modify it (i.e. to temporarily terminate it and thus
11369 // bypass the need for malloc() below) because that might modify the variable contents, and
11370 // that variable may be referenced elsewhere in the body of the loop (which would result
11371 // in unexpected side-effects). So, rather than have a limit of 64K or something (which
11372 // would limit this feature's usefulness for parsing a large list of filenames, for example),
11373 // it seems best to dynamically allocate a temporary buffer large enough to hold the
11374 // contents of ARG1 (the input variable). Update: Since these loops tend to be enclosed
11375 // by file-read loops, and thus may be called thousands of times in a short period,
11376 // it should help average performance to use the stack for small vars rather than
11377 // constantly doing malloc() and free(), which are much higher overhead and probably
11378 // cause memory fragmentation (especially with thousands of calls):
11379 size_t space_needed = ArgLength(1) + 1; // +1 for the zero terminator.
11380 LPTSTR stack_buf, buf;
11381 #define FREE_PARSE_MEMORY if (buf != stack_buf) free(buf) // Also used by the CSV version of this function.
11382 #define LOOP_PARSE_BUF_SIZE 40000 //
11383 if (space_needed <= LOOP_PARSE_BUF_SIZE)
11384 {
11385 stack_buf = (LPTSTR)talloca(space_needed); // Helps performance. See comments above.
11386 buf = stack_buf;
11387 }
11388 else
11389 {
11390 if ( !(buf = tmalloc(space_needed)) )
11391 // Probably best to consider this a critical error, since on the rare times it does happen, the user
11392 // would probably want to know about it immediately.
11393 return MemoryError();
11394 stack_buf = NULL; // For comparison purposes later below.
11395 }
11396 _tcscpy(buf, ARG1); // Make the copy.
11397
11398 // Make a copy of ARG2 and ARG3 in case either one's contents are in the deref buffer, which would
11399 // probably be overwritten by the commands in the script loop's body:
11400 TCHAR delimiters[512], omit_list[512];
11401 tcslcpy(delimiters, ARG2, _countof(delimiters));
11402 tcslcpy(omit_list, ARG3, _countof(omit_list));
11403
11404 ResultType result = CONDITION_FALSE;
11405 Line *jump_to_line = nullptr;
11406 TCHAR *field, *field_end, saved_char;
11407 size_t field_length;
11408 global_struct &g = *::g; // Primarily for performance in this case.
11409
11410 for (field = buf;;)
11411 {
11412 if (*delimiters)
11413 {
11414 if ( !(field_end = StrChrAny(field, delimiters)) ) // No more delimiters found.
11415 field_end = field + _tcslen(field); // Set it to the position of the zero terminator instead.
11416 }

Callers 1

ExecUntilMethod · 0.80

Calls 4

MemoryErrorFunction · 0.85
StrChrAnyFunction · 0.85
omit_leading_anyFunction · 0.85
omit_trailing_anyFunction · 0.85

Tested by

no test coverage detected