So I have this function:
void step (NSTextField *input, char move, int position, NSTextField *label) {
int delta = input.intValue;
for (int i = 0; i < delta; i++) {
pclose(popen("echo move > /dev/tty.usbmodem621", "r"));
position = position +1;
[NSThread sleepForTimeInterval:t1];
NSString *printPosition = [NSString stringWithFormat: #"%i", position];
label.stringValue = printPosition;
}
}
And in the line:
pclose(popen("echo move > /dev/tty.usbmodem621", "r"));
Move should be the variable character that I declared at the beginning. But I can't seem to find out how to do that. Could somebody enlighten me?
Also there is an other thing I don't understand. If for example my input is 20 the and i run this script it counts 20 like it supposed to. However when I input a new value it doesn't ad that one up to the 20 that's already there like I hoped it would. Instead it just displays the new value. Any ideas?
Thanks
To generate string with move:
NSString *str = [NSString stringWithFormat:#"echo %c > /dev/tty.usbmodem621", move];
About not adding more characters, it is hard to say with this example. I can see that your position always starts from 0 because it is incoming parameter but not retuned back. Maybe that's the issue?
This is...not how I would do this. You don’t need to open a pipe or do an echo or any of that stuff to write to a device.
Look into doing something like [NSFileHandle fileHandleForWritingAtPath:#"/dev/tty.usbmodem621”], and then writing to it with writeData:
You can get an NSData from an NSString by using -dataUsingEncoding:, probably with the ASCII encoding.
Yikes. Ok - first problem:
Move should be the variable character that I declared at the beginning
No. popen() executes shell commands and there's no way that it can bind to your move variable. What you need to do is compose a shell command with with move character in it. Something like this
char cmd[] = "echo # > /dev/tty.usbmodem621";
cmd[5] = move;
pclose(popen(cmd,"r"));
Which brings me to the second problem: constructing shell commands from external data and then blindly executing them creates an attack vector called "shell injection" which is quite a common way to hack into systems.
As another poster has already indicated, you don't need popen() to do this so if I were you I'd avoid and never compose shell commands unless you really have to.
Related
I have a NSString variable that contains "{265, 188}". I want just {265, 188} in a variable. What should I do?
Edit:
The code so far is:
//This I get from some XML so I change this part
NSDictionary* controlConditions =#{#"NSPosition":#"{265, 188}"};
NSString* a=(NSString*)[controlConditions valueForKey:#"AXPosition"];
After all, I need to send this to apple script set _controlid_ to a(variable) where i require it to be {265, 188}
Edit:
The variable controlConditions is taken from an XML that gives the position of a UIelement. The NSDictionary returns "{265, 188}" in a(variable). I need to send {265, 188} to an Applescript to match it to the position of various UIelements to get the right one. Hope this makes the problem clearer.
NSString *value = #"{265, 188}";
CGFloat x, y;
sscanf([value UTF8String], "{%lf, %lf}", &x, &y);
NSPoint point = NSMakePoint(x,y);
NSLog(#"%#", NSStringFromPoint(point));
So why don't you just put the values into a fixed array:
int anIntArray[2] = {265,188};
NSLog(#"anIntArray = %d, %d", anIntArray[0], anIntArray[1]);
prints:
anIntArray = 265, 188
Maybe you want to use some type other than int.
The question is really not clear. However, a string of the form {265, 188} is very possibly the result of a previous call to NSStringFromPoint() on an NSPoint whose x field is 265 and y field is 188.
Do you perhaps want to get the NSPoint value back out of the string? If so, you would pass the string to NSPointFromString().
That would not explain how quote characters actually got into the original string, if they are really there. (Unexpectedly, NSPointFromString() actually does still work with a string which contains quote characters.)
Hi i'm trying to get to NSStrings to equal each other in length for a project of mine but i'm seem to be having trouble. I got two string
NSString *word1=#"123456";
NSString *word2=#"123";
I hard coded them to be different lengths for other testing.I'm trying to append 0s at the from of word to so it'll look like #"000123" and i tried this method to append the string but instead it builds up ram and if i leave the program running long enough my system crashes..any help on how to fix this? is there a different method to doing this?
while ([word1 length]>[word2 length]){
[word2 stringByAppendingString:#"0"];
}
while ([word1 length]<[word2 length]){
[word1 stringByAppendingString:#"0"];
}
You are not changing the strings. NSString objects are immutable, you either have to assign the result:
word2 = [word2 stringByAppendingString:#"0"];
or use NSMutableString and appendString:
[word2 appendString:#"0"];
You also have to reverse your logic, as "append" means "add to the end".
append |əˈpɛnd|
verb [ with obj. ]
add (something) to the end of a written document: the results of the survey are appended to this chapter.
You need to change your code to this
while ([word1 length]>[word2 length]){
word2 = [word2 stringByAppendingString:#"0"];
}
while ([word1 length]<[word2 length]){
word1 = [word1 stringByAppendingString:#"0"];
}
I think the reason for the memory increase and app crash is because you are having an infinite loop in your old code. Try putting NSLog into the while loop in your old code and see what is the output. The code I suggested should not have such problem.
I have the following C array of NSString *:
static NSString *const OrderByValueNames[] = {#"None",#"Added",#"Views",#"Rating",#"ABC",#"Meta"};
Now, I want to check the length of this array at runtime so I wrote the following method:
NSInteger LengthOfArray(NSString *const array[])
{
NSInteger length = 0;
// For Loop Without a body!
for (length = 0; array[length] != nil; length++);
return length;
}
Now, when I run this code at debug configuration, everything is fine and the function returns the right result.
BUT as soon as I switch to release configuration and run it again, the program freezes at the for loop. After 10 seconds of the loop being executed, iOS kills the app for not responding. Weird.
Now, if I add body to the loop, like that:
for (length = 0; array[length] != nil; length++)
{
NSLog(#"%d",length);
}
Then it's working fine even in release mode.
Giving the loop an empty body, like that:
for (length = 0; array[length] != nil; length++){}
Still freezes in release mode.
My guess is that there is a compiler optimization when running in release mode, but what exactly?!
Any ideas?
C-style arrays are not nil-terminated by default. If you want to check the length this way, you need to add the terminator yourself.
static NSString *const OrderByValueNames[] =
{#"None",#"Added",#"Views",#"Rating",#"ABC",#"Meta",nil};
A much better way to find the length is simply this:
length = sizeof(OrderByValueNames) / sizeof(OrderByValueNames[0]);
(Note that this trick doesn't work if you pass the array into a function, since it then degenerates into a pointer.)
Your OrderByValueNames array doesn't contain a nil element. No wonder you can't find one! Walking off the end of the array like that will result in undefined behaviour. If you want to mark the end of the array with nil, you'll have to add it manually.
By the way, if you'd like to know the length of a fixed size C array, you can do this:
length = sizeof(OrderByValueNames)/sizeof(OrderByValueNames[0]);
This doesn't work for function parameters, though, as those are just pointers!
I honestly did a) search using key words and b) read the 'questions with similar titles' before asking this.
Also I tried to make this question more concise, but I had a hard time doing that in this case. If you feel the question is too wordy, I get it. Just don't try to answer.
I'm trying to write very simple objective-C programs that mirror the basic assignments in my introductory java class. I worked through an objective-c book over the summer and now I want to do lots of practice problems in objective-c, at the same time as I do java practice problems. I'm avoiding the objective-c GUI environment and just want to focus on working with the language for awhile. I still have a lot to learn about how to figure things out.
The program I'm duplicating from my java homework, is a standard type. I ask the user for number input and string input via the console. I was able to get numeric input from the console using an example I found here using scan f. (I will put the couple code lines below). But I'm unsure on how to get console input and store it in a string (NSString). I'm trying to learn to use the apple documentation and found a reference to a scan type command, but I cannot figure out how to USE the command. The one that seems likely is
scanCharactersFromSet:(NSCharacterSet )scanSet intoString:(NSString *)name;
Here's what I understand and works
int age = 0;
NSLog (#"How old are y'all?");
scanf("%d", &age);
NSLog (#"\n Wow, you are %d !", age);
But I don't understand how to pickup an NSString called 'name'. I THINK I'm supposed to make my 'name'a pointer, because the class is NSString.
(BTW I did try using scanf to pickup the string, but the compiler doesn't like me trying to use scanf in conjunction with name. It says that I shouldn't be using 'scanf' because it's expecting a different kind of data. I'm not sure where I found the data type 'i'. I was looking through my text for different ideas. I'm guessing that scanf is related to 'scanfloat' which clearly deals with numeric data, so this is not a big surprise)
I realize that 'scanf' isn't the right command (and I don't really get why I can't even find scanf in the apple documentation - maybe it's C?)
I'm guessing that scanCharactersFromSet might be the right thing to use, but I just don't understand how you figure out what goes where in the command. I guess I tend to learn by example, and I haven't found an example. I'd like to figure out how to learn properly by reading the documentation. But I'm not there yet.
NSString* name ;
scanf("%i", &name);
//scanCharactersFromSet:(NSCharacterSet *)scanSet intoString:(NSString **)name;
...
My book is oriented towards moving me into a gui environment, so it doesn't deal with input.
Thank you for any pointers you can give me.
Laurel
I would recommend ramping up on C. Objective-c is a thin layer over C and that knowledge will pay for itself over and over.
There's multiple ways in C to read:
http://www.ehow.com/how_2086237_read-string-c.html
For example:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
[pool drain];
return 0;
NOTE: the simple scanf is succeptible to buffer overruns. There's multiple approaches around this. see:
How to prevent scanf causing a buffer overflow in C?
Here is what Objective C looks like:
NSString *FNgetInput() {
#autoreleasepool {
return [[[NSString alloc] initWithData:[[NSFileHandle fileHandleWithStandardInput] availableData] encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
}
The way to get data from the standard input (or any other file handle) in cocoa is to use the NSFileHandle class. Check the docs for +fileHandleWithStandardInput
Here's how to get user input using Objective-C in 2020:
main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
return 0;
}
return 0;
}
Compile and run:
$ clang -framework Foundation main.m -o app
Why 'exactly' does this code loop endlessly if you enter a non number character?
The first question comes about because I want to learn good defensive coding. Does anyone know a good way to check user input? My google-fu failed me. Some people seemed to be of the opinion that if I specify %f in scanf that I am 'demanding' a float; I verified this, in a way, by printing the value of userInput. In fact, if I comment out the do while loop, there is 'no problem' with the execution of the code. It assigns a 0 to userInput and goes about its business.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
float userInput;
float result;
NSLog(#"3X^3 -5x^2 + 6");
do {
NSLog(#"What is x?");
scanf("%f", &userInput);
NSLog(#"userInput = %f", userInput);
} while(userInput == 0);
result = 3 * (userInput * userInput * userInput) - 5 * (userInput * userInput) + 6;
NSLog(#"the result is: %f", result);
[pool drain];
return 0;
}
This is really nothing to do with Objective-C or Cocoa. The issue is simply to do with the use of the standard C library function scanf, and handling the error condition. From the scanf manpage, describing the return code:
Zero indicates that, although there was input available, no conversions were assigned; typically this is due to an invalid input character, such as an alphabetic character for a `%d' conversion.
A valid numeric input can be parsed by scanf with the %f specifier, so that obviously works as expected. But if you enter in a non-numeric character, scanf cannot convert this to a float, and leaves the text in the buffer of stdin. Since the code is not checking the return code from scanf, and only testing if userInput is non-zero, the loop will never exit, as userInput happens to start at 0.0, and will never be updated as scanf will not pull the non-numeric characters out of the stdin buffer. So that is why your code runs in an infinite loop.
If you had initialized userInput to a non-zero value, that would fix the problem one way, as non-numeric input would cause scanf to fail and the while condition would be triggered. But a better fix would be to check the return code of scanf. If it is zero, print an error message, and do a fpurge(stdin) to clear out the invalid input before you loop around again, like this:
int rc = scanf("%f", &userInput);
if (rc == 0)
{
NSLog(#"Invalid input, try again.");
fpurge(stdin);
}
So this is the plain C approach to input and parsing. The bottom line for defensive coding is that you should always check the return code!
As Chris mentions, for an actual Cocoa application, you would want to look at NSNumberFormatter and the like, but then you would presumably be taking input from widgets rather than file streams, so the code would be quite different to the above.
The proper way to validate user input in Cocoa is to use an instance of an appropriate subclass of NSFormatter, in this case something like NSNumberFormatter.