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 have a signal producer, when it's terminated I would like to know if a value was sent, I only need the last one, seems so simple ...
let myProducer: SignalProducer<MyObject, MyError> = getMyProducer()
myProducer.on(terminated: {
// I need the last value here
// Or I need to know if value was never called
}).start()
I've tried to store the value in a local var :
let myProducer: SignalProducer<MyObject, MyError> = getMyProducer()
var myValue: MyObject?
myProducer.on(value: { value in
myValue = value
}, terminated: {
guard let value = myValue else {
// value was never called
return
}
// value was called
}).start()
But sometimes terminated is called while value has been called but myValue is still nil...
First, are you really sure that you want the terminated event?
Under normal conditions, an event stream ends with a completed event. Exceptions are failed when a failure has occurred and interrupted, when the observation was ended before the stream could complete normally (E.g. cancellation).
Second: Can your SignalProducer fail, and in the failure case, do you still want the last value sent before the failure?
If not, its as easy as using the take(last:) operator:
enum MyError: Error {
case testError
}
let (signal, input) = Signal<Int, MyError>.pipe()
let observer = Signal<Int, MyError>.Observer(
value: { print("value: \($0)") },
failed: { print("error: \($0)") },
completed: { print("completed") },
interrupted: { print("interrupted") }
)
signal
.take(last: 1)
.observe(observer)
input.send(value: 1) // Nothing printed
input.send(value: 2) // Nothing printed
input.send(value: 3) // Nothing printed
input.sendCompleted() // value 3 printed
I'm using a Signal here so I can manually send events to it just for demonstration, the same works for SignalProducer as well.
Note: If we send interrupted or a failed event, the last value 3 will not be sent because those to terminating events short circuit the normal flow.
If your SignalProducer can fail, and you still want to get the last value before the failure, you can use flatMapError to ignore the Error before the last operator:
signal
.flatMapError { _ in
return .empty
}
.take(last: 1)
.observe(observer)
my answer :
producer
.flatMapError { _ in SignalProducer<Value, NoError>.empty }
.collect()
startWithResult( { result in
case let .success(results):
done(with: results.last)
case let .failure(error):
() // should not happen as errors are flatmapped
})
I have this token to detect a invalid invoice:
TOKEN : {
< #invalid : <number><client>(<mail> | <mailCom>)<wrongDoc><text><retorn> >
}
And this is my while loop:
while (ok) {
token = app.getNextToken();
switch (token.kind) {
case TextoConstants.client:
System.out.println(token.image);
break;
case TextoConstants.mailCom:
System.out.println(token.image);
break;
case TextoConstants.text:
System.out.println(token.image);
break;
case TextoConstants.invalid:
System.out.println("There is something wrong");
break;
ok = token.kind != TextoConstants.EOF;
}
The problem is when I try to analyze some text block it prints the client/(mailCom)?/text tokens, but no the invalid one.
This is the input:
Number 30003
Client MyName,Lastname
Mail myname#mail.com
DocId 346774
Text
some text block here.
END
The output should be There is something wrong, but instead it prints the other tokens.
Thanks.
Since #invalid starts with a #, it is not a real token kind. It's really just a macro that can be used to define other tokens.
Basically we have quite a few fields within our member search.
We have a few optimized store procedures specifically for certain searches. For example if the user only searches by email address then it would use SearchMemberEmail however if it's search by postcode only then it would use SearchMemberPostcode.
This is all to do with the execution plan in sql server am told.
So we have a LONG ass if statement that basically checks if the the other text boxes are empty. i.e.
if(!string.isnullorempty(Email.Text) && string.isnullorempty(a.Text) && string.isnullorempty(b.Text)
{
Use SearMemberByemail stored procedure
}
The if statement is horrible and hard to read is there a better way of doing this?
You can combine the string.IsNullOrEmpty values to get one number which you can then act on. I only did this as a crude Windows Forms program which displays the intended action in a Label, but it shows the principle:
private void button1_Click(object sender, EventArgs e)
{
int choices = ((string.IsNullOrEmpty(uEmail.Text)) ? 0 : 1) +
((string.IsNullOrEmpty(uA.Text)) ? 0 : 2) +
((string.IsNullOrEmpty(uB.Text)) ? 0 : 4);
switch (choices)
{
case 1:
// search for email
label1.Text = "Email search";
break;
case 2:
// search for A
label1.Text = "A search";
break;
case 4:
// search for B
label1.Text = "B search";
break;
case 6:
// search for A+B
label1.Text = "A+B search";
break;
default:
// general search
label1.Text = "General search";
break;
}
}
Further options would use values of 8, 16, 32...
I have a switch statement in my action script class.I have a function onKeyDown(event: KeyboardEvent) which contain a switch statement.which control the different keys.
But now I want to handle the same functionality which TAB key is doing using two keys CTRL and SPACE key.
I want add a case more in my switch statement first I pressed CTRL and then SPACE key then a a specific function is called.
Anyone can tell me how two keys used in my switch statement?
private function onKeyDown(event: KeyboardEvent) : void{
if (popUp.displayPopUp){
switch (event.keyCode){
case Keyboard.UP:
case Keyboard.DOWN:
case Keyboard.END:
case Keyboard.HOME:
case Keyboard.PAGE_UP:
case Keyboard.PAGE_DOWN:
inputTxt.selectRange(text.length, text.length)
list.dispatchEvent(event)
break;
case Keyboard.ENTER:
acceptCompletion();
break;
case Keyboard.TAB:
if (requireSelection)
acceptCompletion();
else
popUp.displayPopUp = false
break;
case Keyboard.ESCAPE:
popUp.displayPopUp = false
break;
case Keyboard.CONTROL && Keyboard.SPACE:
if (requireSelection)
acceptCompletion();
else
popUp.displayPopUp = false
break;
}
}
}
This is a pretty common problem.
event.keyCode is only going to give you the keyCode for the most recent key pressed. So you will have to store key presses and key releases. Fortunately, AS3 is a pretty sweet Array implementation that allows this to be done easily.
var _keys:Array;
addEventListener(KeyboardEvent.KEY_DOWN, keyDownEvent);
addEventListener(KeyboardEvent.KEY_UP, keyUpEvent);
function keyDownEvent(e:KeyboardEvent)
{
// turn the key on
_keys[e.keyCode] = true;
// perform logic
keyLogic()
}
function keyUpEvent(e:KeyboardEvent)
{
// turn the key off
_keys[e.keyCode] = false;
}
function keyLogic()
{
// this is where the actual logic is
if(_keys[Keyboard.SPACE] && _keys[Keyboard.CONTROL])
{
if (requireSelection)
acceptCompletion();
else
popUp.displayPopUp = false
}
}
This allows you to have a neat little array that always tells you what keys are down. It also separates your program logic from your input logic. Double win.
In your case you can just check ctrlKey property on KeyboardEvent. But #DingoEatingFuzz's answer will allow check combinations like 'space' + 'letter' and so on.
case Keyboard.SPACE:
if (event.ctrlKey)
{
}
break;
i think this one approch is good........