Related
I have a recursive function which iterates though directory trees listing the file names located in them.
Here is the function:
void WINAPI SearchFile(PSTR Directory)
{
HANDLE hFind;
WIN32_FIND_DATA FindData;
char SearchName[1024],FullPath[1024];
memset(SearchName,0,sizeof(SearchName));
memset(&FindData,0,sizeof(WIN32_FIND_DATA));
sprintf(SearchName,"%s\\*",Directory);
hFind=FindFirstFile(SearchName,&FindData);
if(hFind!=INVALID_HANDLE_VALUE)
{
while(FindNextFile(hFind,&FindData))
{
if(FindData.cFileName[0]=='.')
{
continue;
}
memset(FullPath,0,sizeof(FullPath));
sprintf(FullPath,"%s\\%s",Directory,FindData.cFileName);
if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
MessageBoxA(NULL, FullPath, "Directory", MB_OK);
SearchFile(FullPath);
}
else
{
MessageBoxA(NULL, FullPath, "File", MB_OK);
}
}
FindClose(hFind);
}
}
There are obviously differences between both functions but I don't understand what's making them act differently. Does anyone know why I am having this problem?
for fast understand error need look for line
goto label;
//SearchFile(FullPath);
at this point hFind containing valid data and FindClose(hFind); need be called for it. but after goto label; executed - your overwrite hFind with hFind = FindFirstFile(SearchName, &FindData); - so you already never close original hFind, never can return to iterate folder after such go to sub-folder. this is key point - need save original hFind before go to sub directory and restore it after. when you do recursive function call - this is done auto - because every sub directory in this case enumerated in self stack frame, which have separate hFind. this is native solution use recursion here.
but possible convert recursion to loop here because we call self always from the single place and as result to this single place. so we can not save return address in stack but do unconditional jump (goto) to known place.
then code have some extra errors, you never check for string buffers overflow, why 1024 as max length is hard-coded when file path can be up to 32768 chars, you not check for reparse point as result can enter to infinite loop, use FindFirstFile instead FindFirstFileEx, etc.
correct code for enumerate sub-folder in loop can be next
void DoEnum(PCWSTR pcszRoot)
{
SIZE_T FileNameLength = wcslen(pcszRoot);
// initial check for . and ..
switch (FileNameLength)
{
case 2:
if (pcszRoot[1] != '.') break;
case 1:
if (pcszRoot[0] == '.') return;
}
static const WCHAR mask[] = L"\\*";
WCHAR FileName[MAXSHORT + 1];
if (_countof(FileName) < FileNameLength + _countof(mask))
{
return;
}
ULONG dwError;
HANDLE hFindFile = 0;
WIN32_FIND_DATA FindData{};
enum { MaxDeep = 0x200 };
//++ stack
HANDLE hFindFileV[MaxDeep];
PWSTR pszV[MaxDeep];
char prefix[MaxDeep+1];
//--stack
ULONG Level = MaxDeep;
memset(prefix, '\t', MaxDeep);
prefix[MaxDeep] = 0;
PWSTR psz = FileName;
goto __enter;
__loop:
hFindFile = FindFirstFileEx(FileName, FindExInfoBasic, &FindData, FindExSearchNameMatch, 0, FIND_FIRST_EX_LARGE_FETCH);
if (hFindFile != INVALID_HANDLE_VALUE)
{
do
{
pcszRoot = FindData.cFileName;
// skip . and ..
switch (FileNameLength = wcslen(pcszRoot))
{
case 2:
if (pcszRoot[1] != '.') break;
case 1:
if (pcszRoot[0] == '.') continue;
}
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((SIZE_T)(FileName + _countof(FileName) - psz) < FileNameLength + _countof(mask))
{
continue;
}
__enter:
memcpy(psz, pcszRoot, (1 + FileNameLength) * sizeof(WCHAR));
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
DbgPrint("%sreparse point: <%S>\n", prefix + Level, pcszRoot);
}
else
{
if (Level)
{
DbgPrint("%s<%S>\n", prefix + Level, psz);
hFindFileV[--Level] = hFindFile;
pszV[Level] = psz;
memcpy(psz += FileNameLength, mask, sizeof(mask));
psz++;
goto __loop;
__return:
*--psz = 0;
psz = pszV[Level];
hFindFile = hFindFileV[Level++];
DbgPrint("%s</%S>\n", prefix + Level, psz);
}
}
}
else
{
DbgPrint("%s[%u%u] %S\n", prefix + Level, FindData.nFileSizeLow, FindData.nFileSizeHigh, pcszRoot);
}
if (!hFindFile)
{
// top level exit
return ;
}
} while (FindNextFile(hFindFile, &FindData));
if ((dwError = GetLastError()) == ERROR_NO_MORE_FILES)
{
dwError = NOERROR;
}
FindClose(hFindFile);
}
else
{
dwError = GetLastError();
}
if (dwError)
{
DbgPrint("<%S> err = %u\n", FileName, dwError);
}
goto __return;
}
The reason for the difference is actually the confusion brought to you by goto label.If you are using the recursive version, after the recursive execution is completed, it will return to the recursive place to continue execution.
In your code, you continue to execute while (FindNextFile(hFind, &FindData)), but when you use goto label, it will jump out of the original loop and restart the program from the label, which leads to what you said list a single directory tree before ending.
If you modify the modified code to the following iterative version, you can understand why there is such a problem.
void fun()
{
char* Directory = "D:\\test";
HANDLE hFind;
WIN32_FIND_DATA FindData;
char SearchName[1024], FullPath[1024];
char LastName[1024] = "";
while (1)
{
memset(SearchName, 0, sizeof(SearchName));
memset(&FindData, 0, sizeof(WIN32_FIND_DATA));
sprintf(SearchName, "%s\\*", Directory);
if (strcmp(SearchName, LastName) == 0)
{
return;
}
strcpy(LastName, SearchName);
hFind = FindFirstFile(SearchName, &FindData);
if (hFind != INVALID_HANDLE_VALUE)
{
while (FindNextFile(hFind, &FindData))
{
if (FindData.cFileName[0] == '.')
{
continue;
}
memset(FullPath, 0, sizeof(FullPath));
sprintf(FullPath, "%s\\%s", Directory, FindData.cFileName);
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
MessageBoxA(NULL, Directory, "Directory", MB_OK);
char cArray[1024];
memset(cArray, 0, sizeof(cArray));
sprintf(cArray, "%s", FullPath);
Directory = cArray;
break;
}
else
{
MessageBoxA(NULL, FullPath, "File", MB_OK);
}
}
FindClose(hFind);
}
}
}
So you cannot achieve the same purpose as recursion by using goto, here you can only use recursion. Of course, I have provided a way to traverse directories non-recursively using queues, which is a more scientific way.
One of the key things that you obtain from recursion is a separate set of local variables for each call to the recursive function. When a function calls itself, and in the recursive call modifies local variables, those local-variable changes do not (directly) affect the local variables of the caller. In your original program, this applies to variables hFind, FindData, SearchName, and FullPath.
If you want similar behavior in a non-recursive version of the function then you need to manually preserve the state of your traversal of one level of the tree when you descend to another level. The goto statement doesn't do any such thing -- it just redirects the control flow of your program. Although there are a few good use cases for goto in C, they are uncommon, and yours is not one of them.
There are several ways to implement manually preserving state, but I would suggest
creating a structure type in which to store those data that characterize the state of your traversal of a particular level. Those appear to be only hFind and FindData -- it looks like the other locals don't need to be preserved. Maybe something like this, then:
struct dir_state {
HANDLE hFind;
WIN32_FIND_DATA FindData;
};
Dynamically allocating an array of structures of that type.
unsigned depth_limit = DEFAULT_DEPTH_LIMIT;
struct dir_state *traversal_states
= malloc(depth_limit * sizeof(*traversal_states));
if (traversal_states == NULL) // ... handle allocation error ...
Tracking the depth of your tree traversal, and for each directory you process, using the array element whose index is the relative depth of that directory.
// For example:
traversal_states[depth].hFind
= FindFirstFile(SearchName, &traversal_states[depth].FindData);
// etc.
Remembering the size of the array, so as to be able to reallocate it larger if the traversal descends too deep for its current size.
// For example:
if (depth >= depth_limit) {
depth_limit = depth_limit * 3 / 2;
struct dir_state *temp
= realloc(traversal_states, depth_limit * sizeof(*traversal_states));
if (temp == NULL) {
// handle error, discontinuing traversal
}
traversal_states = temp;
}
Also, use an ordinary for, while, or do loop instead of a backward-jumping goto. There will be a few details to work out to track when to use FindFirstFile and when FindNextFile (which you would still have with goto), but I'm sure you can sort it out.
Details are left as an exercise.
Unless necessary due to memory or processing constraints or infinite recursion tail conditions that would be complication to introduce there really isn't much need to not use recursion here, since it leads to a readable and elegant solution.
I also want to point out that in "modern" C, any solution using a GOTO is likely not a solution you want since they are so often confusing to use and leads to memory issues (we have loops now to make all of that so much simpler).
Instead of the GOTOs I would suggest implementing a stack of the directories. Wrap the printing logic a while or do-while, and as you are iterating over the files add any directories to the stack. At every new iteration pop and walk the directory at the head of the stack. The loop condition just needs to check if the directory stack is empty, before continuing its block.
I am trying to create a list which is calculated from another list. For example, if I have a list like 1,2,3,4... then the output has to be 10,20,30,40... Is there any other way to create a list from another in less? Please refer the below codes.
#input: 1,2,3,4;
.for(#array) when (default()) {.for-impl_(length(#array))}
.for-impl_(#i) when (#i > 1) {.for-impl_((#i - 1))}
.for-impl_(#i) when (#i > 0) {.-each(extract(#array, #i), #i)}
.create-list(#input){
.for(#input); .-each(#value, #a) {
.output_#{a}(#a) { // Create dynamic mixin based on input list
#output_#{a}: #a * 10; // Create dynamic variable to store each calc
}
}
}
.create-list(#input);
.loop(#count) when (#count > 0){
#prev: #count - 1;
.loop(#prev);
.first() when (#count = 1){
.output_#{count}(); // call first mixin which created already
#res_#{count}: #output_#{count} // Store the result in another dynamic var
}
.first() when not (#count = 1){
.output_#{count}();
#res_#{count}: #res_#{prev}, #output_#{count}; // join prev and current result
}
.first();
}
.loop(4);
The above implementation similar I expect like below.
.a1(){
#o1: #fff;
}
.a2(){
#o2: #aaa;
}
.a3(){
#o3: #ccc;
}
.loop(#counter) when (#counter > 0) {
.loop((#counter - 1));
.a1();
#out1: #o1;
.a2();
#out2: #out1, #o2;
.a3();
#out: #out2, #o3;
div{
colors: #out;
}
}
.loop(1);
and the output is #fff, #aaa, #ccc.
You'll create a modified "list" by passing the concatenated result of each loop iteration to next iteration, thus the final iteration defines the actual result. E.g. (just illustrating the principle w/o adopting it to your use-case):
// usage:
#input: 1, 2, 3, 4;
result {
.modify-list(#input);
result: #result;
}
// impl:
.modify-list(#list) {
#n: length(#list);
.-(#n, extract(#list, #n) * 10);
.-(#i, #r) when (#i > 1) {
.-(#i - 1; extract(#list, #i - 1) * 10, #r);
}
.-(1, #r) {#result: #r}
}
Demo
Technically this code does not create a one dimensional list (i.e. the result there is not really equal to #result: 10, 20, 30, 40;) but since in final CSS it's rendered identically it would work just fine.
Also assuming your original use-case was How to apply less functions to gradient colors?, you don't really need a code like this (i.e. it's an "XY Problem" and instead of generating a new variable with the new list, direct generation of the corresponding gradient values would be much less verbose and much more readable. See the linked answer in comments of the mentioned question).
I have coded a table driven LR(1) parser and it is working very well however I am having a bit of a disconnect on the stage of turing a parse into a syntax tree/abstract syntax tree. This is a project that I m very passionate about but I have really just hit a dead end here. Thank you for your help in advance.
Edit: Also my parser just uses a 2d array and an action object that tells it where to go next or if its a reduction where to go and how many items to pop. I noticed that many people use the visitor pattern. Im not sure how they know what type of node to make.
Here is the pushdown automata for context
while (lexer.hasNext() || parseStack.size() > 0) {
Action topOfStack = parseStack.peek();
token = parseStack.size() > 0 ? lexer.nextToken() : new Token(TokenType.EOF, "EOF");
topOfStack.setToken(token);
int row = topOfStack.getTransitionIndex();
int column = getTerminalIndex(token.getLexeme());
column = token.getType() == TokenType.IDENTIFIER
&& !terminalsContain(token.getLexeme()) ? 0 : column;
Action action = actionTable[row][column];
if (action instanceof Accept) {
System.out.println("valid parse!!!!!!");
} else if (action instanceof Reduction) {
Reduction reduction = (Reduction) action;
popStack(parseStack, reduction.getNumberOfItemsToPop());
column = reduction.getTransitionIndex();
row = parseStack.peek().getTransitionIndex();
parseStack.push(new Action(gotoTable[row][column]));
lexer.backupTokenStream();
} else if (action != null) {
parseStack.push(actionTable[row][column]);
} else {
System.out.println("Parse error");
System.out.println("On token: " + token.getLexeme());
break;
}
Each reduction in the LR parsing process corresponds to an internal node in the parse tree. The rule being reduced is the internal AST node, and the items popped off the stack correspond to the children of that internal node. The item pushed for the goto corresponds to the internal node, while those pushed by shift actions correspond to leaves (tokens) of the AST.
Putting all that together, you can easily build an AST by createing a new internal node every time you do a reduction and wiring everything together appropriately.
___________________________________________
############################################################################################
FATAL ERROR in
action number 4
of Create Event
for object eng_Global:
DoSet :: Invalid comparison type
at gml_Script_Data_Load (line 1) - ///Data_Load()
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_Data_Load (line 1)
called from - gml_Object_eng_Global_CreateEvent_4 (line 60) - Data_Load();
I get this error on a comment, not an actual if statement, I can't bypass this without commenting out Data_Load(), which is what loads the users' data.
I recently updated to version 1.4.1567, maybe that is a bug in this version.
I should state that "Connected" and "Guest" variables are both integers (boolean) and do not get set to string at any point in the code.
Here is the Data_Load() script:
///Data_Load()
if (Connected && !Guest) {
ini_open(User_Name+"_NSD_Temp.ini");
// Base Statistics
Level = ini_read_real("Statistics","Level",Level);
Exp_Total = ini_read_real("Statistics","Experience_Total",Exp_Total);
Exp = ini_read_real("Statistics","Experience",Exp);
Exp_Left = ini_read_real("Statistics","Experience_Left",Exp_Left);
Exp_Max = ceil(Level*5);
Gold = ini_read_real("Statistics","Gold",Gold);
Gold_Total = ini_read_real("Statistics","Gold_Total",Gold_Total);
Karma = ini_read_real("Statistics","Karma",Karma);
Karma_Total = ini_read_real("Statistics","Karma_Total",Karma_Total);
Highscore = ini_read_real("Statistics","Highscore",Highscore);
Weapons_Inv_Length = ini_read_real("Statistics","Weapons_Inv_Length",Weapons_Inv_Length);
Stones_Inv_Length = ini_read_real("Statistics","Stones_Inv_Length",Stones_Inv_Length);
Stone_Slots_Owned = ini_read_real("Statistics","Stones_Slots_Owned",Stones_Slots_Owned);
// Game
Ninja_Name = ini_read_string("Game","Ninja_Name",Ninja_Name);
Ninja_Level = ini_read_real("Game","Ninja_Level",Ninja_Level);
Ninja_Health = ini_read_real("Game","Ninja_Health",Ninja_Health);
Ninja_Health_Max = ini_read_real("Game","Ninja_Health_Max",Ninja_Health_Max);
Ninja_Health_Regen_Upgrade = ini_read_real("Game","Ninja_Health_Regen_Upgrade",Ninja_Health_Regen_Upgrade);
Ninja_Health_Regen = Ninja_Health_Base*(Ninja_Health_Regen_Upgrade)/room_speed;
Ninja_Weapon = ini_read_real("Game","Ninja_Weapon",Ninja_Weapon);
Ninja_Colour = ini_read_real("Game","Ninja_Colour",Ninja_Colour);
Ninja_Power = ini_read_real("Game","Ninja_Power",Ninja_Power);
Ninja_Max_Speed = ini_read_real("Game","Ninja_Max_Speed",Ninja_Max_Speed);
Ninja_Attack_Speed = ini_read_real("Game","Ninja_Attack_Speed",Ninja_Attack_Speed);
// Weapons Inventory
for (i=0; i<Weapons_Inv_Length; i++) {
Weapons_Inv[i,0] = i;
Weapons_Inv[i,1] = ini_read_real("Weapons Inventory","Inv_Slot_"+string(i),0);
Weapons[Weapons_Inv[i,1],5] = ini_read_real("Weapons Inventory","Inv_Slot_"+string(i)+"_Owned",Weapons[Weapons_Inv[i,1],5]);
}
// Stones Inventory
for (i=0; i<Stones_Inv_Length; i++) {
Stones_Inv[i,0] = i;
Stones_Inv[i,1] = ini_read_real("Stones Inventory","Inv_Slot_"+string(i),0);
Stones[Stones_Inv[i,1],5] = ini_read_real("Stones Inventory","Inv_Slot_"+string(i)+"_Owned",Stones[Stones_Inv[i,1],5]);
}
// Equipped Stones
for (i=0; i<Stone_Slots_Owned; i++) {
Stone_Slots[i,0] = i;
Stone_Slots[i,1] = ini_read_real("Stones Equipped","Slot_"+string(i),Stone_Slots[i,1]);
}
// Costume Colours
for (i=0; i<array_height_2d(Colours); i++) {
Colours[i,5] = ini_read_real("Costume Colours",Colours[i,1],Colours[i,5]);
}
// Stats
Stat_Clouds_Clicked = ini_read_real("Stats","Clouds_Clicked",Stat_Clouds_Clicked);
Stat_Stars_Clicked = ini_read_real("Stats","Stars_Clicked",Stat_Stars_Clicked);
// Options
SoundFX = ini_read_real("Options","SoundFX",SoundFX);
// Version
Save_Version = ini_read_string("Version","Current",Save_Version);
// Resets
ForceResets = ini_read_string("External","Force_Resets",Force_Resets);
ini_close();
if (ForceResets != Force_Resets) {
Data_Erase();
}
Data_Submit();
} // If Connected & Not Guest
GM's compiler is always weird about those line errors. It often doesn't count blank lines as actual lines.
If you adjust for that issue, the real line of code that is throwing the error is this:
if (ForceResets != Force_Resets) {
Maybe it doesn't like that you're basically asking "If something is not equal to itself", which hardly makes sense. That statement will always evaluate to false, so you should probably remove it.
Seeing as you don't declare var on any of these variables, then you're manipulating the variables on the instance that called this script. If there's somehow a ForceResets script variable, and a ForceResets variable on the calling instance, then this whole thing might be a naming issue. I'm also making this assuming because you called:
ForceResets = ini_read_string("External","Force_Resets",Force_Resets);
Where that third parameter isn't declared anywhere in this script.
All in all, I'd say that you need to clean this script up a little.
Pro Tip: Use for(var i = 0; ... instead of for(i = 0 99% of the time. Otherwise you're leaving this instance with an i variable that it will never use.
Here is what I have so far, this is returning two columns, but each counter is stopping and then duplicating the same value over and over...
if(lLogisticsControlTable.APMJobTypeId)
select count (RecID) from jobTypeCheck where jobTypeCheck.APMJobTypeId == lLogisticsControlTable.APMJobTypeId;
{
counter = jobTypeCheck.RecId;
}
while select jobTypeCheck where jobTypeCheck.APMJobTypeId == lLogisticsControlTable.APMJobTypeId
{
counter1 = counter / 2;
halfCount1 = counter - counter1;
if(halfcount <= counter1)
{
halfCount++;
jobListCheck1 = jobTypeCheck.Name;
}
if (halfCount1 > halfCount)
{
halfCount1++;
jobListCheck2 = jobTypeCheck.Name;
}
element.execute(2);
}
}
As Michael Brown indicated, it's difficult to understand the problem with half of the code ;)
However, I would suggest that you call the element.execute(2) method on every second pass through the loop? That way jobListCheck1 would be on the left, and jobListCheck2 would be on the right hand side. Finally you would then need to check immediately outside of your loop if you had an odd number of jobTypeCheck elements, and call the element.execute(2) method one last time remembering to set the jobListCheck2 variable as empty beforehand.
Regards