alex@bilver.UUCP (Alex Matulich) (02/24/90)
Thanks everybody! I got inundated with responses to my C programming questions, and here is the summary, as concise as I could make it. My original post is quoted here with the ">" symbol, and my comments to the answers are indicated. >For the past couple of years I have been writing C programs for IBM >compatibles using either Microsoft C or Turbo C. I try to make my software >look and feel as professional as possible, but during my endeavors I have >run into some programming problems that I can't figure out, and none of >the IBM-specific C programming books I have read are any help. Commercial >programs do these things, so why can't I? COMMENT: Most of the responses I got to my questions were very informative and amounted to a polite way of saying "RTFM". I realized what my problem was: Both the MSC 5.1 and Turbo C 2.0 compilers I use belong to the university I work for, and the MSC manuals do NOT answer my questions, which is why I asked them; the Turbo C manuals do, however the ones I had were from version 1.5 or earlier and I didn't know it! I have been using primarily MSC. Almost every single respondent is a Turbo C user, so many of the responses didn't apply to MSC -- I didn't realize Turbo C was so popular. Anybody know anything about Lattice? >1) Is there a faster way to display character strings than using puts() > or printf() without resorting to assembly language? Use cputs() and cprintf() in the <conio.h> header file. Use putch(), it's "direct video", might be faster than putc()/putchar() Use _write(). It is a direct interface to the DOS write call, and does none of the translations etc. that write() or puts() do. COMMENT: I was hoping to preserve portability in my programs by using cprintf() everywhere, and, in porting it to a non-IBM computer, using #define cprintf printf, but cprintf() doesn't translate the \n character properly, nor does it work with ANSI escape codes. But I do have uses. cprintf() in Microsoft C is just as SLOW as printf()! Turbo C is much faster, but the text doesn't inherit the current stdout text colors. As far as I can tell, _write() needs a file handle, and I don't know how to get a file handle to the video memory. >2) If I have a text screen set up like I want it, is it possible to save > it away somehow so I can display it anytime later by dumping it back > into the video memory? If so, how do I find the address and length > of a video text display? Curses might do this for you. Use gettext(), movetext(), puttext() in <conio.h> For graphics, use _getimage() and _putimage(). On monochrome video cards, (mode 7) the video memory starts at location 0xB000:0000. In all other text modes, video memory starts at 0xB800:0000. Use _getvideomode() to determine whether you're mono or color. The video memory is arranged in row-major order with two bytes per character. Thus, the address of any character on the screen is (base) + (row * 160) + (column * 2). The first byte is the ASCII code for the character, and the second byte is the character's display attribute. COMMENT: gettext(), etc. is only available on Turbo C. My current project is too big to convert to curses, but I'll look for it next time. >3) How do I display inverse, boldface, or multicolored text without > resorting to using ANSI.SYS? Use textbackground(), textcolor() Use textattr() with cputs() in <conio.h> Use escape sequences with puts() (The programs will be portable to non-completely compatible machines if you use the escape sequences) COMMENT: textbackground() and textcolor() aren't available with MSC. Escape sequences don't work with cputs(), cprintf(), etc. but it's not a real problem to use escape sequences with stdout functions when speed doesn't matter. >4) The critical error handler gets invoked when the printer needs more > paper. How do I tell if the printer is offline? The computer hung up > last time I tried using fopen() to get a file handle to a printer that > was powered off. Replace the critical error handler (using the setvect() function) with your own. It should check everything you're interested in, and the rest should be ignored or passed to the original handler. Be sure to replace the original when you're done! Use biosprint() in <bios.h> (Turbo C) Use _bios_printer(_PRINTER_STATUS, ...); (MSC) Some machines have very long timeouts to decide whether or not the printer is offline. You could trap the critical error and check the error code yourself with harderr()/hardretn(). If you need to talk directly to a printer, use stdprn which should be already opened. Write to a file and then pass it to the print spooler and you get background printing and no worries about programs hanging. COMMENT: Hmmm, that's right -- if I wait LONNNG enough, the critical error handler does indeed get invoked with a "device not ready" message. From the responses I got, I gather that there's not really any good way to do this. And how do I access "the print spooler"?? Is it a part of MS-DOS? >5) If a user of my software has a serial printer, how do I set up the > serial port parameters (baud rate, xon/xoff, databits, stopbits, etc)? Use _bios_serialcom() (MSC) Use bioscom() (Turbo C) Let the user take care of this when he installs the printer. It is not likely to change very often; applications should not need to worry about such things. COMMENT: If there's a printer on the serial port, it seems virtually impossible to tell its status without first knowing what kind of printer it is. >6) I expected to find a function somewhere in the standard library that > would read the contents of a disk directory into a string array. Did > I miss it? I have heard the Lattice compiler has such a function, but > I don't have that compiler. If no such function exists, how is it done? You use findfirst() and findnext() to step through the directory one matching entry at a time (this is Turbo C, MSC calls them _dos_findfirst() and _dos_findnext()). Also see getcurdir(), getcwd(). COMMENT: Sure enough, there it is in the MSC manual! The MSC index listed nothing useful under "directory", "directory control", "files", and other obvious headings. _dos_findfirst(), indeed! I never looked at that one long enough to realize what it was. Also, implementation differences between these functions in Turbo C and MSC make for difficult porting. >7) If my PATH environment variable is set up so that I can run one of my > programs from a directory different than the one containing my program, > how it possible for my program to determine the directory IT started > from? Or does that information have to be hard-coded in my program? Look in argv[0], it contains the path of the program. Then use fnsplit() and fnmerge() to manipulate the path. Works under DOS 3.x. Use searchpath(). In version 1.x and 2.x, your best bet is to search the current directory, and then the path, yourself, which is a pain. COMMENT: By golly, it works! I still don't see it in the MSC manual. The only time argv[0] is mentioned is in connection with spawned tasks. >If you know the answers to at least one of the above questions, or if you >know the title of a helpful book I can look up, PLEASE e-mail me a reply. Norton's (Microsoft Press) "Inside the PC" The manuals that came with Turbo C For programming the serial port see The Waite Groupe's MS-DOS Developer's Guide. Hunt, "The C Toolbook" Sam's - Waite Group - Microsoft C for the IBM PC Ray Duncan's Advanced MSDOS (2nd ed.) Peter Norton's Programmer's Guide to the IBM PC Many thanks to all the people who contributed (did I leave anyone out?): uunet!copper.wr.tek.com!michaelk (Michael D. Kersenbrock) uunet!bosco.Berkeley.EDU!raymond (Raymond Chen) RAMontante <uunet!iuvax!bobmon> Dan Kahn <uunet!rufus.math.nwu.edu!kahn> uunet!mitisft!dold uunet!jarthur!dfoster (Derek Foster) uunet!demott.COM!kdq (Kevin D. Quitt) uunet!b.gp.cs.cmu.edu!Ralf.Brown uunet!cis.ohio-state.edu!calvin!richard (Richard Brittain) uunet!hubcap.clemson.edu!wkay (W. Kevin Kay) Rajiv Partha Sarathy <uunet!gpu.utcs.utoronto.ca!sarathy> "Rich Walters" <uunet!math.arizona.edu!arizona!raw> Russell Herman <uunet!me.utoronto.ca!rwh> uunet!att!pegasus!psrc (Paul S. R. Chisholm) uunet!charyb!will (Will Crowder) Tom Wilson <uunet!uhccux.uhcc.Hawaii.Edu!wilson> ucf-cs!cdis-1!tanner CMH117@psuvm.psu.edu (Charles Hannum) -- /// Alex Matulich /// Unicorn Research Corp, 4621 N Landmark Dr, Orlando, FL 32817 \\\/// alex@bilver.UUCP ...uunet!tarpit!bilver!alex \XX/ From BitNet use: bilver!alex@uunet.uu.net
CMH117@psuvm.psu.edu (Charles Hannum) (02/25/90)
I seem to have missed your original posting, so I'll take this opportunity to respond. In article <498@bilver.UUCP>, alex@bilver.UUCP (Alex Matulich) says: > > ... the MSC manuals do NOT answer my questions, which > is why I asked them; the Turbo C manuals do, however the ones I had > were from version 1.5 or earlier and I didn't know it! > > I have been using primarily MSC. Almost every single respondent is a > Turbo C user, so many of the responses didn't apply to MSC -- I didn't > realize Turbo C was so popular. Anybody know anything about Lattice? Probably because Turbo C is *fast*, the integrated environment in one *hell* of a lot better than M*crosoft's, and the manuals are superb! >COMMENT: I was hoping to preserve portability in my programs by using > cprintf() everywhere, and, in porting it to a non-IBM computer, using > #define cprintf printf, but cprintf() doesn't translate the \n character > properly, nor does it work with ANSI escape codes. But I do have uses. > cprintf() in Microsoft C is just as SLOW as printf()! Turbo C is much > faster, but the text doesn't inherit the current stdout text colors. > As far as I can tell, _write() needs a file handle, and I don't know how > to get a file handle to the video memory. Lemme explain ... cprintf(), et al., are specified to write directly to the CON: device (or /dev/ttyxx, or whatever), rather than to stdout or stderr. They are *supposed* to do the same translations as printf() (et al.); I suspect this is why the MSC library routines seem to offer no improvement in speed over the normal printf() routines; this is not what they were meant for. In Turbo C 1.0 (I've had it since the beginning!) the output was sent directly to the MS-DOS console I/O functions (rather than the file I/O functions, which are normally used). However, this didn't follow the definition either, as they could be redirected. Starting with Turbo C 1.5, the console library has forced it to write directly to the screen (literally!!! B-), but it still doesn't do proper translations; you still have to use "\n\r" rather than "\n". <sigh> If you just want to speed up output, and you're displaying line-by-line, use setvbuf(stdout,... _IOLBF ...) (not exactly; fill in the missing arguments!). I don't know about MSC, but this DRAMATICALLY improves performance in Turbo C. (The reason, for those interested, is that Turbo C says "Hey! It's a character device!" and proceeds to write ONE STINKING CHARACTER at a time. With MS-LOSS this is horrendously slow. By using _IOLBF, a whole line is output on each MS-LOSS call. [Note: _IOFBF on an output file is the same in TC as _IOLBF.]) >COMMENT: gettext(), etc. is only available on Turbo C. > My current project is too big to convert to curses, but I'll look for > it next time. I have yet to see a decent (read: REASONABLY FAST) version of Curses! on the PC. If someone actually has a copy, I'd appreciate it, as I don't generally make a habit of porting brain-dead software. >COMMENT: textbackground() and textcolor() aren't available with MSC. > Escape sequences don't work with cputs(), cprintf(), etc. but it's not > a real problem to use escape sequences with stdout functions when speed > doesn't matter. In your portability quest, you are not considering the problem of porting to an entirely different *architecture*. What if you're using a Tektronix terminal on a *nix machine? The escape sequences will be completely different! Your best option, if you want total portability, is to use a *nix-like "termcap" file. >COMMENT: Hmmm, that's right -- if I wait LONNNG enough, the critical error > handler does indeed get invoked with a "device not ready" message. From > the responses I got, I gather that there's not really any good way to do > this. And how do I access "the print spooler"?? Is it a part of MS-DOS? The "print spooler" is PRINT.COM. It's documented in the MS-DOS manual. >COMMENT: Sure enough, there it is in the MSC manual! The MSC index listed > nothing useful under "directory", "directory control", "files", and other > obvious headings. _dos_findfirst(), indeed! I never looked at that one > long enough to realize what it was. Also, implementation differences > between these functions in Turbo C and MSC make for difficult porting. These functions are not derived for any type of standard, and therefore cannot be expected to be portable. Tough. >Look in argv[0], it contains the path of the program. Then use fnsplit() > and fnmerge() to manipulate the path. Works under DOS 3.x. >Use searchpath(). Note: This was in reference to the statement below, which indicates that in DOS -3.00, argv[0] doesn't contain the complete path. >In version 1.x and 2.x, your best bet is to search the current directory, > and then the path, yourself, which is a pain. Note: Version 1.x doesn't use paths. [B-)] >[What books do you recommend?] >The manuals that came with Turbo C You'll get no argument on that one! They're excellent! (Herbert Schildt's?) "Turbo C Pocket Reference". I'm not sure it's ever been updated since version 1.5, but it's still an incredibly useful book. >Many thanks to all the people who contributed (did I leave anyone out?): > > ... >CMH117@psuvm.psu.edu (Charles Hannum) I'm at the bottom of the list! <wimper> B-) Virtually, - Charles Martin Hannum II "Klein bottle for sale ... inquire within." (That's Charles to you!) "To life immortal!" cmh117@psuvm.{bitnet,psu.edu} "No noozzzz izzz netzzzsnoozzzzz..." c9h@psuecl.{bitnet,psu.edu} "Mem'ry, all alone in the moonlight ..."