From: mjd@plover.com (Mark-Jason Dominus) Newsgroups: comp.lang.perl.misc Subject: hard reference problem Date: 30 Dec 1996 05:15:07 GMT Organization: Plover Systems, Philadelphia, PA. Summary: Wrongo, buster. Keywords: Frederic backplane onlooking sloppy In article <32B586D5.2678@mail.g440.com>, Nick Bauman wrote: >Here is my problem code snippet: > >open(EMPLOYEES,'<+/usr/local/etc/httpd/g440/cgi-bin/perl_lib/emp.asc'); >my $Fh = locksmith(\*EMPLOYEES,\*lockType,\*lookIt); > >The problem arises in my referencing the passed filehandle EMPLOYEES in >and out of locksmith, I think. The while (<$Fh>) { } never actually >runs. Why? I've checked the obvious; NO, YOU HAVEN'T. Years ago one of our student programmers asked me what the secret of my programming success was. I told him, and now I will tell you. Come close, so I can yell in your ear. There are actually two secrets. The first secret is: NEVER NEVER NEVER MAKE A SYSTEM CALL WITHOUT CHECKING FOR AN ERROR RETURN Oh, sure. I hear you scoffing, maybe chuckling indulgently. Some secret, you say. Everyone knows THAT. Well, if everyone knows that, how come nobody DOES it? How come YOU didn't do it? Programmers who don't check the return from `open' get POKED. ! Now we're going to DO it. You should take this: open(EMPLOYEES,'<+/usr/local/etc/httpd/g440/cgi-bin/perl_lib/emp.asc'); and write it this way: $FILE = '/usr/local/etc/httpd/g440/cgi-bin/perl_lib/emp.asc'; open(EMPLOYEES, "<+ $FILE") or die "Couldn't open file `$FILE' for reading: $!; aborting"; Maybe something other than `die' is appropriate in your application; we'll stick with `die' here. Hey! I want you to do this, NOW. The next paragraph is going to be my prediction about what is wrong, and if you don't do it now, you won't get a chance to be impressed with my precognitive abilities. EEENY, MEENY, MAGIC BEANIE! THE SPIRITS ARE ABOUT TO SPEAK. Hmmm, I the Great Dominus, predict that---wait as I gaze into my crystal globule, it's becoming clear now---yes, I see a program, lying dead in the snow. But not of natural causes. No, wait, it's speaking, it's saying something, I strain to hear its dying words, and yes, I hear it muttering Couldn't open file `/usr/local/etc/httpd/g440/cgi-bin/perl_lib/emp.asc' for reading: No such file or directory; aborting at line XXXX Zounds, Watson! We may not have found the killer, but now we have a clue: the murder weapon. The game is afoot! Well, if it did say that, it would certainly narrow down your problem, wouldn't it? In particular, you could stop worrying about referencing the passed filehandle and all that other stuff you mentioned, and concentrate on the real problem, which is WHY IT COULDN'T FIND THE FILE. Personally, I dislike these sorts of problems much less than abstruse ones about passing filehandle references. ``The Case of the Missing File'' sounds much more entertaining than ``The Mysteriously Garbled Filehandle Reference.'' Also if you want to write a mystery, you have to have a clue. Now we have a clue. Before all we had was the muddy yard that Legrande and his policemen had been trampling around in all morning. Now comes the interesting part of the problem, which is figuring out why it couldn't find the file. Here it's hard to offer good advice, because this is the part of the problem where it helps to have experience and expertise, there's no big secret there, you just have to practice, practice, practice. If you don't have enough experience and expertise to recognize the problem at this point, that doesn't reflect any discredit on you. That's the point at which you come into the newsgroup, and instead of a big hairy question like the one you asked, you get to say Subject: `No such file or directory' when file exists? ``Why does the `open' here $FILE = '/usr/local/etc/httpd/g440/cgi-bin/perl_lib/emp.asc'; die "File `$FILE' did NOT exist; aborting" unless -e $FILE; open(EMPLOYEES, "<+ $FILE") or die "Couldn't open file `$FILE' for reading: $!; aborting"; fail with `no such file or directory'? I am sure that the file does exist, because the program does not abort at the preceding line.'' This is a lot more likely to get an answer than the question you did ask. I can't write these hundred-line treatises on elementary debugging technique every time, you know. Now you know why it's important to make your mystery entertaining. People aren't in here for their health; they're here to entertain themselves. They answer entertaining questions. You're lucky that I have a very weird idea of entertainment. Anyway, you probably would have gotten two or three responses from people pointing out that the `perlfunc' man page says, under `open': You can put a '+' in front of the '>' or '<' to indicate that you want both read and write access to the file; thus '+<' is usually preferred for read/write updates--the '+>' mode would clobber the file first. Hey, get that? Maybe not; sometimes these things can stare you in the face for days or even weeks before you see them. The `+' goes *in front*. You meant `+<' and you wrote `<+'. What you wrote, `<+ foo', means to open a file named `+ foo' for reading only, so no wonder you got `No such file or directory'. The Case of the Missing File is solved. That does bring up the Second Big Secret, which is ALWAYS READ THE MANUAL . I hate to whack you with this, because you probably do read the manual, but of course sometimes it's hard to know what to read, and I do think this is one of those times. But `open' is failing, and if you did check the manual for `open' you might have seen the problem yourself. Then again maybe not. Well, sometimes you see these things, sometimes you don't. These little typos can be hard to find sometimes. I can't take too much credit; I found it fast because my program had the same problem yesterday. But you're sure not going to find the typos if you don't know where to start looking. You have to start looking in the right places! Where you were looking, you were *never* going to find it. What can we learn from this? 99% of the programmers I have met use Professor Hill's `think method' for debugging. When the program fails, they guess what might be wrong, and then they change the program at random until it appears not to fail any more. That's why the world is so full of cruddy software. I am tired of cruddy software, so cut it the heck out already. What you must do, instead, is include checks in your program. (Even for things that `can't happen'.) If something doesn't check out, print an error message. Then when (not `if') something goes wrong, you can know where it was, and, if you have to guess, at least you can confine your guesses to a very small part of the program. I don't want to rule out the possibility that maybe there *was* a problem in the part of the program you were examining it, but if there is you are much more likely to find it if you know that the file is actually open. OK, now get out there and check those error returns! Hut! -- mjd@pobox.com Mark-Jason Dominus mjd@plover.com Plover Systems, Philadelphia, PA