Jump to content


Check out our Community Blogs

ZekeDragon

Member Since 29 Jul 2009
Offline Last Active May 21 2017 04:37 PM
-----

Topics I've Started

A Short Eulogy to Dennis Ritchie

16 October 2011 - 08:41 AM

Not since Nokola Tesla has such profound genius come, and now passed, so unrecognized. Dennis Ritchie was an inspiration, a visionary, and has permanently influenced the way every one of us as software developers, hobbyists and engineers work. While the world mourns for a salesman, the programming pantheon has lost one of it's brightest stars, without whom we may never have had the most frequently used language and influential operating system ever written.

I've never been any good at these things, and I'm loathe to the fact that I never had the opportunity to know him personally, but unavoidably my life has been touched by Dennis Ritchie. Nearly all of the software technology I use today has been influenced by Dennis Ritchie's creations, be it all the software I use and write in C, the C-syntax languages like C++, Java, and Go, the UNIX-like operating system, or any application and library written to work with these languages or systems. Under appreciated brilliance has been lost, but it is my sincere hope that we do not lose everything that Dennis has given us.

It is rare indeed to find such unfettered passion and deep knowledge even from those who have so shaped the world of computer science as can be found in Dennis Ritchie. Without this treasure of a man, the infrastructure that builds our entire modern software world would be non-existent or dramatically inferior. Any more words would only be a disservice, so all that's left to say is: Dennis, you will be missed, and rest in peace.

The Practical Ramifications of getopt() with Switch Statements

09 August 2011 - 05:52 AM

I was reading through the Darwin 9 Source Code and I noticed something there I pretty frequently see in GNU code, namely the use of getopt() inside of a while with a switch statement to parse arguments given by the user.

This monster is in the disktool source code (in the DiskArbitration folder, licensed under APSL):
while ((ch = getopt(argc, (char * const *)argv, "hrauempndxysgASDl")) != -1)    {
        switch (ch) {
            case 'S':
                vsdbDisplay = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for status\n Usage: disktool -S device\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                }
                break;
            case 's':
                setEncoding = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for encoding\n Usage: disktool -s device encoding\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                    if (argv[3]) {
                        flags = atoi(argv[3]);
                    } else {
                        flags = 0;
                    }
                }
                break;
            case 'g':
                getEncoding = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for encoding\n Usage: disktool -g device\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                }
            case 'r':
                refresh = 1;
                break;
            case 'u':
                do_unmount = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for unmount\n Usage: disktool -u device flags\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                    if (argv[3]) {
                        flags = atoi(argv[3]);
                    } else {
                        flags = 0;
                    }


                }
                break;
            case 'p':
                punmount = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for partition unmount\n Usage: disktool -p device flags\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                    flags = kDiskArbUnmountOneFlag;
                }


                break;
            case 'e':
                eject = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for eject\n Usage: disktool -e device flags\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                    if (argv[3]) {
                        flags = atoi(argv[3]);
                    } else {
                        flags = 0;
                    }
                }
                break;


            case 'A':
                vsdbAdopt = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for adopt\n Usage: disktool -A device\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                }
                break;
            case 'a':
                afpmount = 1;
                if (argc < 5) {
                    (void) printf("disktool: missing device, mountpoint or flags for afp mount\n AFP Usage: disktool -a device mountpoint flags\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                    mountpoint = (char *) argv[3];
                    afpflags = atoi(argv[4]);
                }
                break;
            case 'D':
                vsdbDisown = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for disown\n Usage: disktool -D device\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                }
                break;
            case 'd':
                afpdismount = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for dismount\n Usage: disktool -d device\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                }
                break;
            case 'm':
                do_mount = 1;
                if (argc < 3) {
                    (void) printf("disktool: missing device for mount\n Usage: disktool -m device\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                }
                break;
            case 'n':
                newname = 1;
                if (argc < 4) {
                    (void) printf("disktool: missing device or name for rename\n Usage: disktool -n device newName\n");
                    fflush(stdout);
                    goto Exit;
                } else {
                    device = (char *) argv[2];
                    if (!testDevice(device)) {
                        goto Exit;
                    }
                    mountpoint = (char *) argv[3];
                }
                break;
            case 'x':
                refuse = 1;
                break;
            case 'X':
                refuseMounts = 1;
                break;
            case 'y':
                refuse = 0;
                break;
            case 'l':
                refuse = 0;
                list = 1;
                break;
            case 'R':
                device = (char *) argv[2];
                retain = 1;
                break;
            case 'T':
                device = (char *) argv[2];
                test = 1;
                break;
            case 'E':
                device = (char *) argv[2];
                release = 1;
                break;
            case 'U':
                unrecognizedMessages = 1;
                flags = atoi(argv[2]);
                break;
            case 'V':
                hideUnrecognizedMessages = 1;
                break;
            case 'h':
                DisplayHelp();
                goto Exit;
                break;
            default:
                exit(1);
                break;
        }
    }
I wanted to start a discusson on this practice in particular, and what you think of it. This code is actually pretty sloppy just from looking at it on it's own, since this program doesn't even handle the case of getopt() returning a '?' (which happens when an argument is not recognized), instead leaving it to the default behavior which is to simply exit with failure. You'll probably also notice their use of goto statements, and unfortunately this goto doesn't go to the next line right after the while statement, which would be a reasonable use, and instead jumps right to the end of the main method here:
Exit:

    exit(0);
    //insure the process exit status is 0
        return 0;
    //...and make main fit the ANSI spec.
I'm not interested in the gotos or lack of intelligible error messages for the user, please ignore that, instead I want to know just about the while(getopt()) switch system used to read command line flags in so many C applications. getopt() uses global variables which could make it a poor choice for multithreaded programs, similarly to strtok, but for many command line programs this doesn't matter as they're almost always single thread and, what's more, usually getopt() is done long before you spawn another thread. getopt() also doesn't handle long name flags (e.g. --some-flag), but the GNU extension getopt_long() handles that if you need it. What about if you enter multiple arguments of the same type, does that mean this loop will perform the code twice, and if you give the same flag with two different option values, which one takes precedence? Another thing is GNU getopt()'s tendency to reorganize the passed argv array to place non-option arguments at the back of the array (from which you can use the global variable optind to determine where the non-option args start in argv). I believe Apple uses the BSD version of getopt(), which simply cuts off after it finds the first non-option argument instead of reformatting the argv array (which is why they can pass a char * const *). However, they may be using a modified getopt() that does not change the order of argv in the case of it being const.


My Google-fu skills have not advanced enough to find a general internet consensus on this, so I'm doing the next best thing and asking CodeCall. What do you think of using getopt()? Is it inferior to other, better solutions? Is it hazardous to use in production code? Is it's use perfectly acceptable, just that much like most other C functions it has to be used correctly for it's value to be seen? I leave this to you, CodeCall, give me what you got. :)

Dealing with Checked Exceptions behind an Interface Not Suited for it.

21 April 2011 - 11:43 AM

I've been writing a program to help me at my job recently, sort of as a project to show our IT department the kind of software that I need for my position, I 'spose. Well, one of the things I've been concerning myself with this set of applications and class objects is concurrency, since many of the apps used in RTVHelper (the current working name) are, in fact, multi-threaded. One of the utilities I'm developing for this set of software is something I'm calling the "ReentrantReadWriteCollectionsWrapper", an unnecessarily long-named object that wraps around objects that implement the Collections interface and provide for it thread-safety through Reentrant locks using the java.util.concurrent.ReentrantReadWriteLock object. Anyway, when dealing with these locks, it's possible that while a thread is awaiting a lock from the ReentrantReadWriteLock, that it will be interrupted. If this happens, the object will throw an InterruptedException, and this is the crux of my problem.

Since I have to implement the Collection interface for this object (as it is supposed to be a wrapper), none of the methods can be flagged to throw InterruptedException as that is not part of the object's expected interface. If I accept that and make the interface of this wrapper incompatible with the Collection interface, then this object will not be able to take advantage of methods coded to the Collection interface. I can also throw a RuntimeException, which doesn't necessarily break the interface, but it does introduce the sudden possibility that every method in the object can throw a RuntimeException, which, depending on where in the execution Thread 1 is in the middle of using the ReentrantReadWriteCollectionsWrapper, when Thread 2 interrupts Thread 1, the Collection being executed with Thread 1 WILL throw that RuntimeException and if there's no handler will forcibly close the Java App. Simply put, I'd much rather not use a RuntimeException. I could silently ignore the InterruptedException and set a flag in the object, but then the program relies on the client checking this flag, and what's more, methods working on Collections won't look for this flag so if the interruption occurs rather early in the method, there's a lot to ignore, and no way to tell just how far into the method it was done before the interruption occurred. Finally, I also attempt to come up with some kind of static behavior to handle InterruptionException, but this leaves the client of the Wrapper no alternatives or options.

I just wanted to see if you guys had any good ideas for what to do with this? Maybe there's something I hadn't considered yet.

What's your Comment Policy?

02 February 2011 - 10:26 AM

Anyone who's maintained software long enough knows the value of well-placed, explanatory comments. Good comment work can make the difference between a 10 minute tweak and a 6 hour code revision, so we all (or at least most of us), but a few comments in here and there to, at the very least, remind ourselves what exactly we were thinking when we wrote the code. Well, this post is for you to talk about how you go about commenting. Explain, if you will, what you do when faced with the need to explain yourself?

If anyone's seen my recent code, they'd know I'm very liberal with my spacing and I comment like a freak. This is because I actually write my comments before my code, and I use those comments as the basis for how I write the code. I essentially write what I want to do, and an explanation of how I intend on doing it, and then write the code that does it. If there's problems, I rewrite my comment and change the code. This has given me a significant advantage when I go back and start looking at this code again, since if nothing else it allows me to know what I was thinking, which is important as it gets me back into the mindset.

My comments have a sort of "flow of consciousness" feel to them, which does present what many people would say is a problem, IE I have too many superfluous comments. However, I've made it a point to work on hedging my comments when I'm done and all-in-all I'd say it looks pretty good.

What do you do? I'm on my lunch break right now or I'd provide examples... I'll post some when I get back from work. Until then... I'd like to see yours!

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download