greyelf@wpi.WPI.EDU (Michael J Pender) (11/08/90)
I'm trying to read and write binary files from Hyper C.
Would someone with the documentation please tell me how?
This was my closest attempt:
#include <st.h>
main()
{
char *screen;
FILE *fp = open("/ram/output.snd","wb");
for(screen = 0x400; screen < 0x8; screen++)
fprintf(*fp, "%x", *screen);
close(fp);
exit();
}
Please reply REAL SOON. I need to have these routines working by 11:00
friday...
---
Michael J Pender Jr Box 1942 c/o W.P.I. Part of this D- belongs to
greyelf@wpi.bitnet 100 Institute Rd. God...
greyelf@wpi.wpi.edu Worcester, Ma 01609 - B. Simpson
--
---
Michael J Pender Jr Box 1942 c/o W.P.I. Part of this D- belongs to
greyelf@wpi.bitnet 100 Institute Rd. God...
BRL102@psuvm.psu.edu (Ben Liblit) (11/09/90)
In article <1990Nov8.045226.7696@wpi.WPI.EDU>, greyelf@wpi.WPI.EDU (Michael J Pender) says: > >I'm trying to read and write binary files from Hyper C. >This was my closest attempt: [ I have omitted below all lines except those requiring modification. ] >#include <st.h> Unless you renamed it, this should be <std.h>. > FILE *fp = open("/ram/output.snd","wb"); ProDOS HyperC takes no second parameter -- if specified, it is ignored. (Yes, HyperC does absolutely no parameter checking.) > for(screen = 0x400; screen < 0x8; screen++) You want to scan as long as "screen < 0x800", not "screen < 0x8". Also, although HyperC couldn't care less, it is good programming practice to typecast the 0x400 and 0x800 to char pointers. More strict compilers will call you nasty names if you don't. > fprintf(*fp, "%x", *screen); Ok, here's the core of the problem. As I stated above, ProDOS HyperC takes only one parameter for open(). What this means is that it doesn't know the difference between binary and text files. It's all in how your program chooses to read and write the file. fprintf() is for text files ... for binary files, use read() and write(). Both take three parameters: first, the file designator (just as in fprintf()); second, a buffer usually de- clared as an array of or pointer to char; lastly, an integer specifying the length of the buffer in bytes. For those applications where only one byte (char) is being written at a e time, the most efficient technique would be to use putc(). It takes two parameters: first, the file designator as in fprintf(); second, the char- acter to be written. So instead of your fprintf() call, you really want: putc( *fp, *screen ); Actually, if all you're doing is a straight screen dump to disk, you can do the whole thing *really* efficiently using: write( *fp, (char *) 0x400, 0x400 ); and eliminate the loop completely. -- Hope this helps. -- Ben Liblit BRL102 @ psuvm.bitnet -- BRL102 @ psuvm.psu.edu "Fais que tes reves soient plus longs que la nuit."
BRL102@psuvm.psu.edu (Ben Liblit) (11/10/90)
A few clarifications to my recent posting concerning binary files in HyperC: FILE open( TEXT *fname ); ------------------------- The open() function returns a FILE, not a pointer to a FILE. Since, in HyperC, FILE is simply an int, you can really mess things up if you're careless about your pointers. HyperC couldn't care less if you assign an int to a pointer or vice versa. It's up to the programmer to watch out for this. Yes, open() does *not* take a second parameter. ProDOS, and therefore HyperC, could not care less wether you are opening to read or write, or text versus binary. It's up to you, the programmer, to deal with files in the proper manner. FILE create( TEXT *fname ); --------------------------- open() will *not* create a new file. To start a new file, you should use create() instead. create() actually performs three calls to the operating system, through MLI: destroy, create, and open. Call it as you would call open(), and remember that it takes care of opening the file for you (i.e., don't follow up create() with a call to open()). INT getc( FILE fd ); -------------------- This returns a single character from the given file. Again, watch those pointers! The return value is an int, not a char, so that -1 can be returned on errors. VOID putc( FILE fd ); --------------------- The counterpart to getc(), this function writes a single byte to the given file. It does *not* have a specified return value. Error Codes ----------- Create(), open(), and getc() return -1 to indicate an error condition. Additionally, the actual ProDOS error code is placed in _ioresult. Declare "extern int _ioresult;" if you wish to access it. The linker will resolve the reference. On the other hand, read(), write(), and putc() will *not* return -1 to signal an error. Read() and write() return simply the actual number of bytes read or written. Putc()'s return value is *unspecified*. If an error occurs, all three of these function *will* set _ioresult to the ProDOS error code. For most applications the use read() and write(), it should not be necessary to check _ioresult after each call. Instead, simply compare the *requested* number of bytes with the *actual* number of bytes. If they're different, something went wrong. This works especially well for checking for EOF after a read() call. If EOF was reached, read() will return fewer bytes than were requested. One final note -- don't use read() and write() for characters. Yeah, they'll work, if you get the parameter types cast just right, but it's not worth it. Use putc() and getc() instead ... they're quicker, require less code, and much easier to use. And whatever you do, don't call printf( fd, "%c", letter ) !!! Can you say "unnecessary overhead"? I new you could. Ben Liblit BRL102 @ psuvm.bitnet -- BRL102 @ psuvm.psu.edu "Fais que tes reves soient plus longs que la nuit."
toth@tellabs.com (Joseph G. Toth) (11/15/90)
I have tried mailing this, but my mailers keep rejecting the address -------------------------- Michael, It has been a while since I played with HyperC, and I only have a few of my listings here at work with me, so I can't totally guarantee the accuracy of everything I say here. In response to some of the questions in your recent posting; A) How do I create my own libraries? from the command prompt, enter 'mkdir <path>' in program code, Sorry, I haven't figured that one out yet, using the create didn't work for me. Looks like it will have to be written in assembler as a separately linked in function. B) Can the sym function do anything useful? Absolutely, Try using it once on the supplied archive libraries. You will find all kinds of useful info (however, I somehow assumed that you did this to be able to find out the entry point names in rt65.o to be able to generate your assembly routine graphics functions. C) How does one make an independent system program using Hyperc? Well, this will take a lot of work. I know the steps but not the details, and the details will require a lot of investigation. 1 - examine the format of the link command, you will notice an very short file (named s.o) that gets linked in before it processes any of your files. It is the first entry after the -a, followed by the $1 (for which the shell script substitutes your object file). You can even create your own archives and include them here if you have a large program or a bunch of nice short functions (a good place for separately compiled graphics functions, anybody ever create a Unix-like Curses package for an Apple //). This entry is the startup code that has external references to exit() and main(). This must be re-created where it provides all of the operations that the HyperC shell provides before executing your program. These include; a) loading the 'HYPERC' code at its appropriate location in memory ( I will explain shortly ). b) create a stack frame and initialize all required variables. c) parse the command to pass the parameters (argc, argv) to main. d) calling the main program with the argc and argv parameters. e) providing a call to exit() in case the program simply returns (does not perform its own call to 'exit()') I almost forgot, but 'exit()' will hace to be re-written to provide the standard ProDOS exit operation, as the current 'exit()' appears to return control to the HyperC shell by some method other than restarting the shell via the ProDOS 'quit' code. be a non-standard method. The reason for loading the HYPERC code is that it contains much of the operational code required by the linked operations. You may think you are including 'open', 'close', 'printf', etc. in your linked executable, but you are not. Those, and many other functions, are actually contained in the HYPERC code. Go back to question B - look at the output. The letters have meaning; A - anchored location T - an entry point in the object file X - an external entry referenced by code in the object. Watch the output on the screen while a link is in progress. Ever wonder why the insertion address of an included object didn't change from one file to the next? The answer is that that object only contained Anchored entries and variable definitions (no actual code). The numbers following an A in the symbol table listing is the PHYSICAL address in the Apple's memory where other objects containing an external reference will access. It would probably be safest to have the startup code load the HYPERC code since it is possible that code in rt.o, or any other supplied archive entry, could have direct calls to code in the HYPERC code whthout showing up in the Symbol Table dump. D) What is the name and function of all assembler directives? I have no idea. E) How many 65c02 codes are supported? I read somewhere that an assembler directive selects c02 code and that all op codes were supported. Sorry, a haven't found that info yet, will still look. F) What is the syntax for 65c02 codes implemented with implied operands? But you said you already know. I hope I was able to provide some useful information, even though I know I couldn't give any easy solutions. Joe Toth Tellabs, Inc. Lisle, Il.