NSUserDefault and Negative numerical arguments (Was: Posting mouse clicks with multiple displays)

  • When using NSUserDefaults to get command line arguments, it doesn't
    seem to handle negative numbers correctly.
    In main.m:
      NSUserDefaults *args = [NSUserDefaults standardUserDefaults];

      int x = [args integerForKey:@"x"];
      int y = [args integerForKey:@"y"];
    If the command line is "MyApp -x -100 -y 100", NSUserDefaults does not
    recognize the -100 as the value of the x argument - it sets x to 0.
    If the '-' is removed, everything is fine.  Is this a bug?  Is there a
    way around?
    Thanks again!
    Sean DeNigris
    <sean...>
  • On Jul 29, 2009, at 7:09 PM, DeNigris Sean wrote:
    When using NSUserDefaults to get command line arguments, it doesn't
    seem to handle negative numbers correctly.
    > In main.m:
    > NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
    >
    > int x = [args integerForKey:@"x"];
    > int y = [args integerForKey:@"y"];
    > If the command line is "MyApp -x -100 -y 100", NSUserDefaults does
    > not recognize the -100 as the value of the x argument - it sets x to
    > 0.  If the '-' is removed, everything is fine.  Is this a bug?  Is
    > there a way around?

    Yes-- -100 is parsed as an argument, not as a value to the previous
    argument.

    b.bum
  • On Jul 29, 2009, at 8:22 PM, Bill Bumgarner wrote:

    > On Jul 29, 2009, at 7:09 PM, DeNigris Sean wrote:
    > When using NSUserDefaults to get command line arguments, it doesn't
    > seem to handle negative numbers correctly.
    >> In main.m:
    >> NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
    >>
    >> int x = [args integerForKey:@"x"];
    >> int y = [args integerForKey:@"y"];
    >> If the command line is "MyApp -x -100 -y 100", NSUserDefaults does
    >> not recognize the -100 as the value of the x argument - it sets x
    >> to 0.  If the '-' is removed, everything is fine.  Is this a bug?
    >> Is there a way around?
    >
    > Yes-- -100 is parsed as an argument, not as a value to the previous
    > argument.

    So, no, it isn't a bug.  It is behaving correctly, for some values of
    correct.  Welcome to shell programming & the interface between shell
    & process.  Fragile space. Coder beware.

    If you are writing a command line tool, you'll want to use a parsing
    API that actually lets you specify arguments more completely.

    man 3 getopt

    That'll give you a start.  But I'd recommend Dave Dribin's DDCLI
    stuff;  http://www.dribin.org/dave/blog/archives/2008/04/29/ddcli/

    If this is a Cocoa application, you'll want to do the command line
    parsing *before* NSApplicationMain() is called as it'll munch the
    arguments beyond recovery IIRC.

    b.bum
  • >>> In main.m:
    >>> NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
    >>>
    >>> int x = [args integerForKey:@"x"];
    >>> int y = [args integerForKey:@"y"];
    >>> If the command line is "MyApp -x -100 -y 100", NSUserDefaults does
    >>> not recognize the -100 as the value of the x argument - it sets x
    >>> to 0.  If the '-' is removed, everything is fine.  Is this a bug?
    >>> Is there a way around?
    >>
    >> Yes-- -100 is parsed as an argument, not as a value to the previous
    >> argument.
    >
    > So, no, it isn't a bug.  It is behaving correctly, for some values
    > of correct.  Welcome to shell programming & the interface between
    > shell & process.  Fragile space. Coder beware.

    I consider that if a negative number is a valid value for an option,
    and NSUserDefaults can not handle them, and this restriction is not
    documented, then it's a bug.

    Non-bug options would be:
    a) handle negative arguments correctly
    b) restrict numerical arguments to positive values and document this
    restriction

    The behavior of the object does not match the spec.
  • On 11 Aug 2009, at 17:14, DeNigris Sean wrote:

    >>>> If the command line is "MyApp -x -100 -y 100", NSUserDefaults
    >>>> does not recognize the -100 as the value of the x argument - it
    >>>> sets x to 0.  If the '-' is removed, everything is fine.  Is this
    >>>> a bug?  Is there a way around?
    >>>
    >>> Yes-- -100 is parsed as an argument, not as a value to the
    >>> previous argument.
    >>
    >> So, no, it isn't a bug.  It is behaving correctly, for some values
    >> of correct.  Welcome to shell programming & the interface between
    >> shell & process.  Fragile space. Coder beware.
    >
    > I consider that if a negative number is a valid value for an option,
    > and NSUserDefaults can not handle them, and this restriction is not
    > documented, then it's a bug.

    So file a bug report.

    > Non-bug options would be:
    > a) handle negative arguments correctly
    > b) restrict numerical arguments to positive values and document this
    > restriction
    >
    > The behavior of the object does not match the spec.

    The documentation barely specifies how parsing works for command line
    arguments at all.  For instance, it's clearly the case that YES and NO
    work for boolean arguments.  But that isn't documented anywhere and it
    means that if you want a string containing "YES" or "NO" you're going
    to be out of luck.

    So I don't think it's a case of the behaviour not matching the spec.
    There *is* no spec worth mentioning, so really if there's a bug here,
    it's that the docs don't say how the argument domain works.

    *Anyway*, my impression has always been that NSUserDefaults was not
    intended to be used to obtain the command line arguments, and that the
    argument domain feature was put there primarily (though perhaps not
    exclusively) for debugging purposes, as a way of temporarily
    overriding the settings in the defaults database.

    If you want to process the command line arguments, you can either do
    so from your main() function, before calling NSApplicationMain(), or
    you can use NSProcessInfo to examine them once your app is running.

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
  • On Aug 11, 2009, at 9:14 AM, DeNigris Sean wrote:
    >>> NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
    >>>
    >>> int x = [args integerForKey:@"x"];
    >>> int y = [args integerForKey:@"y"];
    >>> If the command line is "MyApp -x -100 -y 100", NSUserDefaults does
    >>> not recognize the -100 as the value of the x argument - it sets x
    >>> to 0.  If the '-' is removed, everything is fine.  Is this a bug?
    >>> Is there a way around?
    >
    > I consider that if a negative number is a valid value for an option,
    > and NSUserDefaults can not handle them, and this restriction is not
    > documented, then it's a bug.

    But this has nothing to do with NSUserDefaults and everything to do
    with command line arguments.

    When parsing the command line arguments, how does the application know
    that "-x means that the next argument must be parsed as a number"?

    In short, it can't unless you use something somewhere to effectively
    express the schema of your command line arguments.  Since there is no
    schema associated with NSUserDefaults, the problem can't be solved
    there.

    > Non-bug options would be:
    > a) handle negative arguments correctly
    > b) restrict numerical arguments to positive values and document this
    > restriction
    >
    > The behavior of the object does not match the spec.

    It does.  The spec simply does not encompass providing the schema
    necessary to parse the command line arguments.

    See 'man getopt' then go google 'getopt better command line parsing'.

    b.bum
  • On 11 Aug 2009, at 9:47 AM, Alastair Houghton wrote:

    > On 11 Aug 2009, at 17:14, DeNigris Sean wrote:
    >
    >>>>> If the command line is "MyApp -x -100 -y 100", NSUserDefaults
    >>>>> does not recognize the -100 as the value of the x argument - it
    >>>>> sets x to 0.  If the '-' is removed, everything is fine.  Is
    >>>>> this a bug?  Is there a way around?
    >>>>
    >>>> Yes-- -100 is parsed as an argument, not as a value to the
    >>>> previous argument.
    >>>
    >>> So, no, it isn't a bug.  It is behaving correctly, for some values
    >>> of correct.  Welcome to shell programming & the interface between
    >>> shell & process.  Fragile space. Coder beware.
    >>
    >> I consider that if a negative number is a valid value for an
    >> option, and NSUserDefaults can not handle them, and this
    >> restriction is not documented, then it's a bug.
    >
    > So file a bug report.
    >
    >> Non-bug options would be:
    >> a) handle negative arguments correctly
    >> b) restrict numerical arguments to positive values and document
    >> this restriction
    >>
    >> The behavior of the object does not match the spec.
    >
    > The documentation barely specifies how parsing works for command
    > line arguments at all.

    Current behavior is that anything with a leading `-` is considered a
    flag; therefore "MyApp -x -100 -y 100" looks like a command-line
    invocation with three flags, one of which has a value (the `y` flag).

    Without some additional information about expected types for a given
    flag (or whether a given flag requires an argument, etc) we can't do
    much better. You can file a bug against NSUserDefaults; it's likely to
    wind up a dup of an existing bug we have to tell NSUserDefaults what
    to expect for a particular flag.

    > For instance, it's clearly the case that YES and NO work for boolean
    > arguments.  But that isn't documented anywhere and it means that if
    > you want a string containing "YES" or "NO" you're going to be out of
    > luck.

    NSUserDefaults supports a few different accessors for values:

    - (NSString *)stringForKey:(NSString *)defaultName;
    - (NSArray *)arrayForKey:(NSString *)defaultName;
    - (NSDictionary *)dictionaryForKey:(NSString *)defaultName;
    - (NSData *)dataForKey:(NSString *)defaultName;
    - (NSArray *)stringArrayForKey:(NSString *)defaultName;
    - (NSInteger)integerForKey:(NSString *)defaultName;
    - (float)floatForKey:(NSString *)defaultName;
    - (double)doubleForKey:(NSString *)defaultName;
    - (BOOL)boolForKey:(NSString *)defaultName;

    So given this command-line:

    ./foo_tool -booleanOption YES

    if you were to ask NSUserDefaults for -stringForKey:@"booleanOption"
    you'd get back the NSString @"YES". If you were to ask NSUserDefaults
    for -boolForKey:@"booleanOption" you'd get back (BOOL)1.

    > So I don't think it's a case of the behaviour not matching the
    > spec.  There *is* no spec worth mentioning, so really if there's a
    > bug here, it's that the docs don't say how the argument domain works.

    Please file a bug against the documentation to be clearer about what
    to expect.

    > *Anyway*, my impression has always been that NSUserDefaults was not
    > intended to be used to obtain the command line arguments, and that
    > the argument domain feature was put there primarily (though perhaps
    > not exclusively) for debugging purposes, as a way of temporarily
    > overriding the settings in the defaults database.

    As usual, it depends on what you're trying to do. Many command-line
    tools use NSUserDefaults to get their arguments; it's a lot easier
    than using getopt(3) most of the time. You're correct

    > If you want to process the command line arguments, you can either do
    > so from your main() function, before calling NSApplicationMain(), or
    > you can use NSProcessInfo to examine them once your app is running.

    You can always do this if you know a particular key hasn't been
    handled the way you expect via NSUserDefaults.

    .chris

    --
    Chris Parker
    iPhone (formerly Cocoa) Frameworks
    Apple Inc.
  • On Tue, Aug 11, 2009 at 9:47 AM, Alastair
    Houghton<alastair...> wrote:
    > If you want to process the command line arguments, you can either do so from
    > your main() function, before calling NSApplicationMain(), or you can use
    > NSProcessInfo to examine them once your app is running.

    I believe I suggested that at one point, but it was pointed out to me
    that NSApplicationMain irreversibly munges argv before NSProcessInfo
    accesses it.

    --Kyle Sluder
  • On Aug 11, 2009, at 10:04 AM, Kyle Sluder wrote:
    On Tue, Aug 11, 2009 at 9:47 AM, Alastair
    > Houghton<alastair...> wrote:
    >> If you want to process the command line arguments, you can either
    >> do so from
    >> your main() function, before calling NSApplicationMain(), or you
    >> can use
    >> NSProcessInfo to examine them once your app is running.
    >
    > I believe I suggested that at one point, but it was pointed out to me
    > that NSApplicationMain irreversibly munges argv before NSProcessInfo
    > accesses it.

    What Alastar said;  you have free reign over argv/argc prior to
    calling NSApplicationMain().

    b.bum
  • > What Alastar said;  you have free reign over argv/argc prior to
    > calling NSApplicationMain().

    Duh!  You're right, I will just process them myself! I don't know why
    I was so attached to making NSUserDefaults do what I wanted it too -
    probably lack of sleep and frustration with the documentation.
  • On Aug 11, 2009, at 10:31 AM, DeNigris Sean wrote:
    >> What Alastar said;  you have free reign over argv/argc prior to
    >> calling NSApplicationMain().
    >
    > Duh!  You're right, I will just process them myself! I don't know
    > why I was so attached to making NSUserDefaults do what I wanted it
    > too - probably lack of sleep and frustration with the documentation.

    Hardly;  it would be a very desirable feature to have in the 'kit.

    Actually, I would recommend that you grab DDCLI -- Dave Dribin's
    command line argument processing toolkit.  If you are building a
    Foundation Tool or an NSApp that can take arguments, it is a must-have.

    Fortunately, the license is MIT and, thus, you can use it without
    restriction.

    http://www.dribin.org/dave/blog/archives/2008/04/29/ddcli/

    b.bum
previous month july 2009 next month
MTWTFSS
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
Go to today