phd@speech1.cs.cmu.edu (Paul Dietz) (08/03/88)
I'm tired of fighting this one. Does anybody know how to delete characters when you make a mistake typing during an LSC scanf? Any suggestions would be appreciated. Thanks! Paul H. Dietz ____ ____ Dept. of Electrical and Computer Engineering / oo \ <_<\\\ Carnegie Mellon University /| \/ |\ \\ \\ -------------------------------------------- | | ( ) | | | ||\\ "If God had meant for penguins to fly, -->--<-- / / |\\\ / he would have given them wings." _________^__^_________/ / / \\\\-
beard@ux1.lbl.gov (Patrick C Beard) (08/03/88)
In article <2559@pt.cs.cmu.edu> phd@speech1.cs.cmu.edu (Paul Dietz) writes: >I'm tired of fighting this one. Does anybody know how to delete >characters when you make a mistake typing during an LSC scanf? >Any suggestions would be appreciated. Thanks! > >Paul H. Dietz ____ ____ The answer to your question is, DON'T USE SCANF! I have always hated the way scanf treats the user who assumes he can edit his command line. A better approach to getting lines of input and parsing them from the user is to use gets() and then sscanf(). For example: Instead of: float foo() { float in_value; printf("enter a floating point value: "); scanf("%f",&in_value); /* yuck, user can't edit his input! */ return(in_value); } use: float foo() { float in_value; char buf[80]; /* overconservative */ printf("enter ... "); gets(buf); /* user can use backspace to edit */ sscanf(buf,"%f",&in_value); return(in_value); } I hope this helps. +=============================================================+ | Patrick C. Beard | | Lawrence Berkeley Laboratory | | Automated Supernova Search | +-------------------------------------------------------------+ | PCBeard@LBL.gov (arpa only) | +=============================================================+
suitti@haddock.ISC.COM (Steve Uitti) (08/04/88)
In article <587@helios.ee.lbl.gov> beard@ux1.lbl.gov (Patrick C Beard) writes: >In article <2559@pt.cs.cmu.edu> phd@speech1.cs.cmu.edu (Paul Dietz) writes: >>I'm tired of fighting this one. Does anybody know how to delete >>characters when you make a mistake typing during an LSC scanf? >>Paul H. Dietz > >The answer to your question is, DON'T USE SCANF! I have always hated >the way scanf treats the user who assumes he can edit his command line. Under UNIX, the user typically can edit the command line. The Mac interface doesn't really have a command line, so scanf must implement one. >A better approach to getting lines of input and parsing them from the user >is to use gets() and then sscanf(). For example: >float foo() >{ > float in_value; > char buf[80]; /* overconservative */ > > printf("enter ... "); > gets(buf); /* user can use backspace to edit */ > sscanf(buf,"%f",&in_value); > return(in_value); >} Under UNIX, scanf lets you edit stuff. Trouble is, if (for example) input is redirected from a file, and the pattern scanf wanted didn't exist in the file, it would infinite loop. This is bad. One more step - "gets" doesn't do bounds checking. Most C compilers still do all floating point with doubles. For exmple, most compilers still actually convert floats to doubles when passing values to/from subroutines. I don't know offhand if LSC does this. #include <stdio.h> /* define stdin */ #define BS 80 /* often good enough */ double foo() { double in_value; char buf[BS]; printf("enter ... "); if (fgets(buf, BS, stdin) == NULL) { /* handle the EOF error */ } if (sscanf(buf, "%lf", &in_value) != 1) { /* handle the parsing error - expected one conversion */ } return in_value; } Programs should be written such that they can't over run buffers. When (not if) errors happen, they should be handled gracefully. All of them. Another of the problems with sscanf (the only remotely useful function in the series) is that it doesn't tell you much about why it couldn't do something (if it even tells you that it couldn't do something). Thus, not only do I never use "scanf" or "fscanf", I seldom use "sscanf". The LSC standard C library isn't the most robust. It does "seem to work" for most things, and the "console" window is utterly painless. The compiler itself does seem to be robust, produces code that runs pretty quickly, and produces it VERY quickly. If I were to write Mac applications, there wouldn't be a second choice development environment. (A fully blown Mac II with two monitors and LSC 3.0 is really hard to beat). Stephen Uitti
strasser@murdu.OZ (Mike Strasser) (08/04/88)
In article <587@helios.ee.lbl.gov> beard@ux1.lbl.gov (Patrick C Beard) writes: [quote from Paul Dietz] >The answer to your question is, DON'T USE SCANF! I have always hated >the way scanf treats the user who assumes he can edit his command line. >A better approach to getting lines of input and parsing them from the user >is to use gets() and then sscanf(). For example: [etc.] The problem with doing your own buffering via gets(), strings and sscanf() is when you want a flexible interface where a user can type more than one item on a line. You then need to parse the line yourself (when scanf() on an input stream will do that adequately) or find a way of knowing how much of the string has been parsed by sscanf(), so second and subsequent calls will not start at the beginning of the string again. --------------------------------------------------------------------------- Mike Strasser ACSnet, CSnet: strasser@murdu.oz Internet: strasser%murdu.oz@uunet.uu.net Forestry Section University of Melbourne Creswick, Victoria. 3363 Phone: (053) 45 2405 A u s t r a l i a +61 53 45 2405 ---------------------------------------------------------------------------
swilson%thetone@Sun.COM (Scott Wilson) (08/04/88)
scanf is not a useless function! While I believe that to approach 100% bullet-proof i/o you have to do everything yourself one character at a time, scanf is still useful. The problem is that most people don't know how to use scanf. Consider this example: #include <stdio.h> main() { int i; do { printf("Enter a number between 1 and 100: "); scanf("%d", &i); } while (i < 1 || i > 100); printf("You typed: %d\n", i); } This is a common problem when using scanf. The user types a letter, scanf pushes it back and the program goes into an infinite loop (assuming the garbage value of an uninitialzed i is out of range). The solution: don't use scanf? Not necessarily. Scanf returns a value to help out in this situation. From the Sun0S 4.0 scanf man page: scanf() returns the number of successfully matched and assigned input items; this number can be zero in the event of an early conflict between an input character and the con- trol string. The constant EOF is returned upon end of input. Note: this is different from 0, which means that no conversion was done; if conversion was intended, it was frustrated by an inappropriate character in the input. Now I know that I have seen some scanfs that return something different like the number of characters read. ANSI should clear this up (using the above I think). My LSC manual is at home so I don't know what that scanf returns. So we change the example to this: #include <stdio.h> main() { int i; do { printf("Enter a number between 1 and 100: "); if (scanf("%d", &i) != 1) { while ((i = getchar()) != '\n') /* skip bad stuff */ ; i = 0; /* or something else out of range */ } } while (i < 1 || i > 100); printf("You typed: %d\n", i); } Note that the program does not go into an infinite loop because the offending character that caused scanf not to match a decimal integer has been removed from the input stream. -- Scott Wilson arpa: swilson@sun.com "Why do dogs lick Sun Microsystems uucp: ...!sun!swilson their balls? Because Mt. View, CA they can!"
phd@speech1.cs.cmu.edu (Paul Dietz) (08/04/88)
I asked: >>>I'm tired of fighting this one. Does anybody know how to delete >>>characters when you make a mistake typing during an LSC scanf? Apparently, noboby condones the use of scanf: >>The answer to your question is, DON'T USE SCANF! >Thus, not only do I never use "scanf" or "fscanf", I seldom use "sscanf". SO: What do you use for input on your quick little pieces of code???? Since I move code freely back and forth between UNIX and the Mac, I'd like a solution which works equally well on both. My first idea was to fix the scanf routine in the LSC library to handle deletes properly. Unfortunately, this looked like a great deal of work. (Apparently, the routine does not buffer the input...) Next idea was to write a macro to replace scanf with the appropriate fgets and sscanf calls. This stumbled when I realized I didn't know how to write macros which took variable number of arguments. The last idea was to write my own general scanf replacement and use it everywhere, but this failed with my not knowing a machine independent way of moving the cursor and deleting characters. So, what should I do??? Help..... Thanks! Paul H. Dietz ____ ____ Dept. of Electrical and Computer Engineering / oo \ <_<\\\ Carnegie Mellon University /| \/ |\ \\ \\ -------------------------------------------- | | ( ) | | | ||\\ "If God had meant for penguins to fly, -->--<-- / / |\\\ / he would have given them wings." _________^__^_________/ / / \\\\-
swilson@sun.uucp (Scott Wilson) (08/04/88)
In article <62725@sun.uucp> swilson@sun.UUCP (Scott Wilson) writes: >scanf is not a useless function! While I believe that to approach 100% >bullet-proof i/o you have to do everything yourself one character at a >time, scanf is still useful. The problem is that most people don't >know how to use scanf. Consider this example: This bit was really intended to describe the usefulness of scanf on other systems such as UNIX. I agree that LSC's scanf leaves something to be desired in terms of error correction. At least the 3.0 version is better than the 2.15 version which didn't echo what you typed (at least that's how I remember it, I could be wrong, ever since I tried to bitch about a bug that was my own stupidity I don't trust myself anymore). So I guess scanf is not good for much in LSC after all. I really wish ANSI could do something for us here, but I'm told it doesn't. Scott Wilson
jdevries@zodiac.ads.com (Jeff De Vries) (08/05/88)
If memory serves, I believe that LSC provides separate functions for handling interactive I/O. I think the functions are called cscanf (for console scanf) cprintf (for console printf) (Someone with a manual handy can very if I'm out in lala land) Jeff De Vries jdevries@ads.com (ARPA) /* usual disclaimer */
oster@dewey.soe.berkeley.edu (David Phillip Oster) (08/07/88)
In article <587@helios.ee.lbl.gov> beard@ux1.lbl.gov (Patrick C Beard) writes: >{ > float in_value; > char buf[80]; /* overconservative */ > > printf("enter ... "); > gets(buf); /* user can use backspace to edit */ > sscanf(buf,"%f",&in_value); > return(in_value); >} Are you from the moon? Why would anyone want to do such a silly thing? The correct solution is: #if MAC #include <DialogMgr.h> #define TEXTITEM 3 /* GetDIHandle - return handle from current dialog item */ Handle GetDIHandle(item)short item;{ short type; Handle hand; Rect r; GetDItem(thePort, item, &type, &hand, &r); return hand; } /* foo- get a floating point number from the user */ float foo(){ float f; Str255 s; SetPort(GetNewDialog(FLOAT1, NIL, -1L)); for(;;){ ModalDialog(NIL, &item); switch(item){ case OK: GetIText(GetDIHandle(TEXTITEM), s); PtoCstr( (char *) s); if(1 != sscanf(s,"%f", &f) || OutOfBounds(f)){ /* bad number, beep and reselect */ SysBeep(1); SelIText(thePort, TEXTITEM, 0, 9999); break; } DisposDialog(thePort); return f; /* user wants out */ case Cancel: DisposDialog(thePort); return BADFLOAT; /* user wants out */ } } } /* Where FLOAT1 is the resource id of a dialog with an okay button as item 1, a cancel button as item 2, an edit text box as item 3, and a prompt statictext string as item 4. Just create it in ResEdit. */ #else ... whatever ludicrous nonsense you have to do on other machines #endif Get with it guys, this is Macintosh, not some 1960's vintage teletype. --- David Phillip Oster --When you asked me to live in sin with you Arpa: oster@dewey.soe.berkeley.edu --I didn't know you meant sloth. Uucp: {uwvax,decvax,ihnp4}!ucbvax!oster%dewey.soe.berkeley.edu