From: Tim Swenson To: 100031.2312@CompuServe.com, 70004.75@compuserve.com, Date: Wed, 9 Sep 92 14:36:23 EDT Full-Name: Tim Swenson@Program Support Subject: QL Hacker's Journal Q L H A C K E R ' S J O U R N A L ---------------------------------------------------------- Number 10 Sept 1992 ---------------------------------------------------------- The QL Hacker's Journal (QHJ) is an amateur publication published by Tim Swenson strictly as a hobby and as a service to the QL Community. The QHJ is copyright by Tim Swenson and respective contributers, but may be freely copied and distributed (please do) to all QL users. The QHJ is always interested in article submissions. If interested, please send mail to the address below (Snail Mail or E-Mail). Electronic copies of the QHJ are available on disk or via e-mail from: QL Hacker's Journal c/o Tim Swenson 4773 W. Braddock Rd. #3 Alexandria, VA 22311 (703) 820-6657 tswenson@sesky4102b.pl.osd.mil tswenson@dgis.dtic.dla.mil Editor's Forumn This issue is the second issue to take 3 months to come out. I had not planned on a quarterly schedule, but it has come out that way. There are two primary reasons for this delay: 1) My daughter is now crawling and requires more supervison and this means I have to do my share. 2) I've hit a writer's block as far as programming. I have all sorts of ideas, but most are longer programs. With the time that I have to sit at the computer, I really can only work on short (but interesting) programs, and I've had a lack of ideas for these type of programs. If anyone has any ideas, please send them my way. In the article below on Maus.sys.ql, there is some discussion of putting QL executables on to FTP servers (Unix boxes). I've done some testing and have verified that when a file is transfered to MS-DOS or Unix, the header information is lost. This means that all executables will no longer execute. Some people have taken this to mean that only source code and text files be put on FTP servers. I don't agree with that. I've looked at a couple of QL data archivers (HAR, Lhx, and ZOO) and find that only HAR will restore the file header information with the file. This means that executable can be archived with HAR, put on an FTP server, unarchived later, unarchived, and run. To test this, I took the archived YACC file, transfered it to MS-DOS, and back from MS-DOS. I then unarchived the YACC file (using HAR) and made sure the Yacc executable would execute. In fact, in the HAR documentation it mentions that it does retain all of the QL header information. HAR is Public Domain (but really Freeware). Using HAR as a compressor/archiver, I have uploaded QED, EFORTH, YACC, and FLEX, to the QL FTP Server garbo.uwasa.fi. The files were uploaded to /ql/incoming. As this issue is going to press, I have just recieved a copy of C68 3.0. I have heard that it is a little on the buggy side. I will give it a try. I have also heard that Bob Dyl of the "International QL Report" has received C68 3.02, which is supposed to fix all the bugs of 3.0. I am sending disks to Bob to get version 3.02 and hope to have a review for the next issue. In the same package that I received 3.0, received a copy of the Spectrum emulator for the QL. I have not had a chance to even look at the disk, so I will have more to say on it next issue. Programmer's Bookshelf By Tim Swenson Over the years I have picked up a number of computer books. Some I have purchased for classes, others I have bought out of my own interest. I have also scoured various libraries to see what sort of selection of computer books they have. Through all of this I have come across books that I feel should be in every programmer's personal library. Some are for general programming, others are more language specific. I don't believe my list is complete as I am always reading books that I am happy to discover are "classics." General Programming: "Elements of Programming Style" by Kernighan and Pike is a classic. It's second edition has been in print since 1978 and could stand to be updated. It's examples are in Fortran, a language now almost out-dated. Some of thier rules are aimed at Fortran and like languages. But overall it covers all aspects of writing good code. ( I got lucky and found my copy at a library book sale for 50 cents :-) ) "Software Tools" by Kernighan and Plauger. This book defined what is meant by software tools and how they are used together to solve problems. It covers the basic tools used in UNIX and other operating systems, like COUNT (wc), EDIT (ed), FORMAT (nroff like), etc. "Mythical Man-Month" - I've forgotten the author's name, but this book has been around for years, so it should be easy to find. The author was involved with the development of OS/360 for IBM. He has taken what he learned from that and other projects, and created a book that details the process of software project management. A must read if you work with a number of programmers on a project. "Programming Pearls" and "More Programming Perls" by Jon Bently. Jon used to write a column called "Programming Pearls" for "Communications of the ACM". These columns have been worked into two books. They cover programming topics in an easy to read manner with lots of sample code. The second book is the better of the two. I found the chapter dealing with Little Languages inspiring. "The Knuth Books" - I can't remember the names of the three volume set, but this alias should be recognized by all. Don Knuth has written three volumes of a projected 7 volume set. The most popular of the three is the one on sorting. This book covers all aspects of sorting. The are two problems with these books: One, they are tough to read. They are written for those familiar with college level math. And, secondly, they are not cheap. The current cost per volume is about $50-60 (and this is a rough guess). Language Books: "The C Programming Language" by Kernighan and Ritchie (first and second edition). This book is know simply as K&R. To distinquish between the editions most people say K&R 2nd Ed. and K&R 1st Ed. If you program in C, this is the book to get. Personally, I have both editions. "The AWK Language" by Aho, Weinberger, and Kernighan. This is THE book for AWK. It is in the same style and approach as K&R. It's small, compact, and easy to read. "Postscript" - There is a series of books on Postscript put out by Adobe that are very good. If you need to learn Postscript, these books cover it all. I don't know of any other books that are the definitive for thier respective language. BASIC is too diverse to have one grand reference book. I do have a T/S 1000 ROM disassembly book that I will never part with. At the very least I can use it to study how a computer ROM is done. Source Books: "PC-SIG Directory" - Even though I am mostly a QL user, I do have an IBM laptop that I use. The PC-SIG directory is a source to hundreds of free/shareware disks. Plus the PC-SIG library is available via ANON-FTP. "C Users Group Library Volumes 1-3" - The C Users Group (who publish the "C Users Journal") is a good source for free C source code. They carry C source from the CP/M world, MS-DOS, OS-9, and UNIX. For other computers they will put it in thier library, but have an outside person support copying it for them. If there is enough support, they might even list stuff for the QL. Other Books: "Fire in the Valley" by Swaine and Freiburger. This book throughly covers the start of the personal computer industry in Silicon Valley. It does stray out of the valley to cover MITS in New Mexico and some events on the east coast. It does not cover any computer development in Europe. There is one slight mention about Sinclair computers and one picture of Sir Clive Sinclair. "Hackers" by Steve Levy. This book is best for its coverage of the hacker phenomonon at MIT in the early and late sixties. It really covers how computer programming as a passion got started. Does cover Steve Wozniac and Sierra On-Line, the software company. "Cookoo's Egg" by Clifford Stoll. This is a great book to curl up with. It covers the break-in and capture of some German crackers that tried to break into some American systems. Very easy to read. This book was used as the basis for a NOVA (PBS) episode. "The Devouring Fungus" by Karla Jennings. This book is a collection of humorous computer stories, most taken from the Internet. Some of the stories I have heard before, others were new to me. Good light reading. This is just my list. I'm interested in hearing other opinions. Let me know what other books I should add to the list. Maus.sys.ql By Tim Swenson In the European part of Usenet, there is a newsgroup called Maus.sys.ql. This newsgroup is for the discussion of all things QL. Due to the low numbers of American QLers that read Usenet, a Usenet feed has not been established. I have established an e-mail feed from the newsgroup. This means that all articles posted to maus.sys.ql will be mailed to my e-mail account. Others that would like this service can contact Jeorg_Lehers@arbi.informatik.uni- oldenburg.de. I can also send all that I get to others. Just send me a note. To post messages from the Internet, send a mail message to: maus.sys.ql@arbi.Informatik.Uni- Oldenburg.de. For the European readers, there is a number of BBS's (called QBOXnet) that carry the same articles. Below is a list of them: Fourth Dimension +44-202600305 (England) Grizzilius Maximus +44-772828975 (England) TF Services +44-717062379 (England) Blanford BBS +44-258455117 (England) Aspects +44-617920260 (England) Quanta NE BBS +44-914775472 (England) Jamten TCL +46-64133330 (Sweden) Andromeda BBS +39-6-3251114 (Italy) Lau's Place +44-253780021 (England) SYNCNET +31-35-237178 (Holland) QLAT +31-30-962265 (Holland) KU-EL-TEL +31-1650-37105 (Holland) Here are some of the more interesting tidbits coming out of the newsgroup: From Dave Walker: I would like to know how the EJC libraries have been made fully re-entrant and romable. About 90% of library routines refer to glogal variables such as 'errno' in real C programs. This makes it rather difficult to write properly re-entrant code. I agree that individual routines that make this assumption CAN be made romable, but that does not solve the generic problem - it just means that you can write single routines that are romable. Peter Sulzer replies: I can tell you, I've written a reentrant, ROMable startup module for Lattice some time ago (but was too lazy to write a library - it was long before C68, and I'm afraid the C68 libs must be rewritten for that startup module). You use option -b in the first compiler phase (OK you know this). Now comes the trick, your startup module allocates the memory for all the static data, e.g. in a "data-job". Then you copy all static data (in fact one must only copy the static initialised data) to the allocated memory. Of course your static data area is limited to max. 64 K - in fact I found no way to force the linker to use a +32K offset enabling static data from -32K to +32K. It worked only with an offset of 0, so the max. static data is 0 to +32K. Of course one must also usse option -r in the second phase, limiting the code size of the program to max. 32K (perhaps less - at least with my startup module). I assume text87 plus4 does the same, cause you can save memory when you have executed it, if you make it non-reentrant so that the static data mustn't be copied. From Jan Bredenbeek: I have the runtime version of C68 v3.01 for download or file request on my board. File names are C68V301A.ZIP, C68V301B.ZIP, C68V301C.ZIP for the contents of Disk 1, 2, and 3 respectively. Beware though: The three files are together 800K in size (300 for A and 250 for each of the other two) so if you're calling from outside the Netherlands it's better to use a 9600+ modem, unless you have access to a phone line you can use on someone elses dime :-). (See SYNCNET in the above list) From Franz Herrmann: I can only repeat that neither any part of C68 itself nor any compiled prog worked on an ExeQtor machine, Gold Card v2.25. We tried it with Minverva and MGG ROM. No difference. We loaded Pointer Environment, Lighting, etc., removed the extensions piece by piece to find out which was causing the crashes. Even on the plain machine, nothing worked. Possibly GC v2.28 fixes that. I don't know, I am just reporting what I saw (Fortunately, I have no probs on my own QLs.) From Franz Herrmann: Dave, Some notes on C68 v3.01, which is simply excellent, ..C68 does not report an error with such a definition: static char *test = "Hello World" (static char test[] = ... would be correct) Instead C68 runs into an endless loop!!! (C68 v2.x accepted the fault!) Peter Sulzer replies: >Right, I looked at K&R, both are legal. They are not completely different but exactly the same. ^^^^^^^^^^^^^^^^^^^^^ Sorry Franz, you think wrong :-) static char *test = "Hello World" defines a pointer ( one longword in C68) which points to the string "Hello World". The pointer may be at a totally different location in memory than the string itself. static char test[] = "Hello World" defines a vector of char, 12 bytes long, containing the characters 'H','e',... 'd','\0'. The first construct needs 12+4=16 bytes, the second 12 bytes. Erik Slagter replies: What Peter Sulzer says holds ONLY within a struct or union. Anywhere else it implies THE SAME level of indirection namely one. The only difference of *test and test[] outside the struct/union is that test[x] may be altered and *(test+x) may not be altered. This is because space is allocated for test[x] on the stack whilst *test points to a location in program memory. From Dave Woodman: Further to my last message, the source files for the QDOS port of cpp have now been uploaded to garbo.uwasa.fi and may be found under the /ql/unsorted. Please not that the file is in zip format. All those with anonymouse ftp may snarf to their hearts content. Yes, Peter, you are right:- ascii files only on garbo! PGM and PBM to QL By Herb Schaaf [ Editor's Note - There is a Freeware Unix package called PBMPLUS that converts to/from a number of graphics formats. It does this by using three intermediate formats, PBM, PGM, and PPM. Herb Schaaf has written a C program that will convert a PGM and PBM file to the QL. Since the conversion is going from a large number of colors to only 8, don't expect the results to be astonishing. I find it interesting to see Herb take the time to figure out the PGM and PBM file formats and how to convert them to the QL. Both of us hope that some of you will find it usefull.] /* pgmtoql8_c Sample C Program to read a * file such as al125.pgm (pixel gray scale) * and display on QL in 8 color mode * May 22, 1992 9am */ #include #include #include #include #define MAX_I 130 /* maximum image dimension */ /* based on 2x2 block size */ #define LEFT_EDGE 126 /* for image out screen */ char _PROG_NAME[] = "pgmtoql8"; struct QLRECT grawin, *grwin; FILE *fp_grwn; /* file pointer for graphic window */ FILE *fp_in; /* file pointer for input images */ unsigned char in_image[MAX_I*MAX_I]; /* input image array */ unsigned char out_image[MAX_I*MAX_I]; /* output image array */ unsigned char rid_one[1]; /* get 'rid' of one byte */ char img_type[6]; /* image file type (P5 = gray) */ char filein[36]; /* input file name */ char grayvals[4]; /* keyboard input values */ long width, height; /* input image width, height */ int max_color, max_count; /* maximum color value */ int present; /* number of color values found */ int pixels; /* number of pels read in from file */ long colors[256]; /* histogram of density ? */ long maxcount; /* highest count in colors[] */ int color; /* for colors[] */ int levels; /* number of grey levels */ int row, col, block; /* loop control values */ int x, y, w, h; /* QLRECT values */ long to_grwn, to_in; int count; main() { /* get name of image file */ printf("name of image file ?\nsuch as flp2_AL125_PGM or\nflp2_MNDRL125_PGM\n"); gets(filein); printf("%s\n",filein); /* open image file to read */ fp_in = fopen(filein,"rb"); /* read binary file */ if (fp_in == NULL) { printf("Error Opening image file %s\n",filein); printf("Touch ENTER"); getch(); exit(1); } to_in = getchid(fileno(fp_in)); printf("opened input file #%u located at %u\n",fileno (fp_in), fp_in); /* set mode, etc. */ grwin = &grawin; mt_dmode("8","0"); fp_grwn = freopen("scr_512x256a0x0","w",stdout); to_grwn = getchid(fileno(stdout)); sd_bordr(to_grwn,-1,2,2); sd_setst(to_grwn,-1,6); sd_setpa(to_grwn,-1,6); sd_setsz(to_grwn,-1,1,0); sd_setin(to_grwn,-1,1); grwin->q_width = 256; w = grawin.q_width; grwin->q_height = 256; h = grawin.q_height; grwin->q_x = LEFT_EDGE; x = grawin.q_x; grwin->q_y = 0; y = grawin.q_y; sd_clear(to_grwn,-1); sd_clear(stderr,-1); /* read header information */ printf("Reading Header information\n - - - \n\n"); read_pgm_header(fp_in); printf("\nplease wait - - reading pixels\n"); if((width >= MAX_I) || (height >= MAX_I)){ printf("%d wide by %d high is oversize\n",width, height); printf("limit is %d x %d\n",MAX_I-1,MAX_I-1); printf("\n touch [space-bar] to exit"); getch(); exit(1); } /* read image into 1 dimensional array */ pixels = fread(in_image, sizeof(unsigned char),width* height,fp_in); fclose(fp_in); printf(" %d pixels\n\n",pixels); /* 'grey' shades */ printf("gray shades ? 2 to 255 "); gets(grayvals); printf(" %s\n",grayvals); levels = 256 / (atoi(grayvals)); /* Histogram ? */ sd_setin(to_grwn,-1,0); for (row = 0; row <= (pixels/width); row++) { for (col = 0; col <= width; col++) { color = in_image[col + (row*width)]; colors[color] = colors[color] + 1; } } printf("touch ENTER\n"); getch(); /* find maximum and missing values */ maxcount = 0; present = 256; printf("values missing for:\n"); for (count = 0; count <= 255; count++) { if(maxcount < colors[count]) { maxcount = colors[count]; max_count = count; } if(colors[count] == 0) { printf("%4d",count); present--; } } printf("\n%d values found \n%d has the maximum count of %d\n", present, max_count, maxcount); printf("\ntouch ENTER\n"); getch(); sd_bordr(to_grwn,-1,0,0); sd_clear(to_grwn,-1); /* draw lines */ sd_iscale(to_grwn,-1,256,0,0); for (count = 0; count <= 255; count++) { sd_iline(to_grwn,-1, 0,count, colors[count], count); } sd_pos(to_grwn,-1,20,22); printf("touch ENTER\n"); getch(); /* change by some function for new output file */ /* let's try dividing into grey levels */ /* or the inversion idea 255 - value */ /* set size of block for pixelating */ block = 2; grwin->q_width = block; w = grawin.q_width; grwin->q_height = block; h = grawin.q_height; for (row = 0; row <= (pixels/width); row++) { grwin->q_y = 0+(block*row); y = grawin.q_y; for (col = 0; col <= width; col++) { grwin->q_x=LEFT_EDGE+(block*col); x = grawin.q_x; out_image[col + (row*width)] = in_image[col + (row*width)] / levels; /* now we need a little plotting going on */ sd_fill(to_grwn,-1,out_image[col + (row*width)] ,grwin); } } /* hang on until we see it */ grwin->q_width = 512; w = grawin.q_width; grwin->q_height = 256; h = grawin.q_height; grwin->q_x = 0; x = grawin.q_x; grwin->q_y = 0; y = grawin.q_y; sd_setin(to_grwn,-1,0); getch(); printf("ENTER to leave"); getch(); fclose(fp_grwn); exit(0); } int getint(fp) /* from John Bradley's */ FILE *fp; /* XV version 2.00 */ { /* as of 02/01/92 */ int c, i; int garbage, numgot=0; /* skip ahead */ c = getc(fp); while(1) { /* comments ? */ if (c == '#'){ /* found a comment */ while(c != '\n' && c != EOF) { c = getc(fp); printf("%c",c); } } if (c == EOF){ return 0; } if ( c >='0' && c <= '9') break; /* found a number */ if ( c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ',') garbage = 1; c = getc(fp); } /* go until non-number */ i = 0; while(1){ i = (i*10) + (c - '0'); c = getc(fp); if ( c == EOF) return i; if ( c < '0' || c > '9') break; } numgot++; return i; } read_pgm_header(fp) FILE *fp; { int c, c1, file_type; c = getc(fp); c1 = getc(fp); if(c!='P' || c1<'5' || c1>'6') { printf("PGM error: unsupported format.\n"); printf("Must be raw grayscale or color.\n"); getch(); exit(1); } img_type[0]=c; img_type[1]=c1; img_type[3]='\0'; printf("Image type: %s\n",img_type); width = getint(fp); printf("%d wide\n",width); height= getint(fp); printf("%d high\n",height); max_color = getint(fp); printf("%d colors\n",max_color); if ( max_color <= 0){ printf("PGM error: Garbage in Header\n"); getch(); exit(1); } return (c1-'0'); } /* end of pgmtoql8_c May 22, 1992 noon */ /* pbmtoql2C_c * H. L. Schaaf * Program to read a bit mapped black/white file * such as ram2_out_pbm from RDSphere programs * and display on QL in 2 color mode, block size == 1 * compensates for density by discounting guide boxes etc. * compile with %300000 -bufp150K * returns 96% and 20% memory usage * June 3, 1992 11:15 */ #include #include #include #include #include #include #define MAX_W 512 /* maximum image dimension */ #define MAX_H 256 /* based on 1x1 block size */ #define LEFT_EDGE 0 /* for image out screen */ #define IMAGE_DOTS 86400 /* assumes 360 x 240 */ char _PROG_NAME[] = "pbmtoql2C"; struct QLRECT grawin, *grwin; FILE *fp_grwn; /* file pointer for graphic window */ FILE *fp_in; /* file pointer for input images */ unsigned char in_image[MAX_H*MAX_W];/* input image array */ char img_type[6]; /* image file type (P4 = b&w) */ char filein[36]; /* input file name */ int width, height; /* input image width, height */ int img_bytes; /* number of bytes in image */ int row, col, block; /* loop control values */ int x, y, w, h; /* QLRECT values */ long to_grwn, to_in; /* QL channel id */ int bp, img_byte, count, ort; unsigned char bit_string[9]; int byte_count, wite_count, hite_count; main() { /* get name of image file */ sd_clear(fgetchid(stdout),-1); printf("name of image file ?\nsuch as flp1_SP1_PBM \n"); gets(filein); printf("\n%s\n",filein); /* open image file to read */ fp_in = fopen(filein,"rb"); /* read binary file */ if (fp_in == NULL) { printf("Error Opening image file %s\n",filein); printf("Touch [space-bar]"); getch(); exit(1); } to_in = getchid(fileno(fp_in)); printf("opened input file #%u located at %u\n",fileno (fp_in), fp_in); printf("\n touch [space-bar]\n"); getch(); /* set mode, etc. */ grwin = &grawin; mt_dmode("4","0"); fp_grwn = freopen("scr_512x256a0x0","w",stdout); to_grwn = getchid(fileno(stdout)); sd_bordr(to_grwn,-1,0,0); sd_setst(to_grwn,-1,6); sd_setpa(to_grwn,-1,7); sd_setsz(to_grwn,-1,1,0); sd_setin(to_grwn,-1,0); grwin->q_width = 512; w = grawin.q_width; grwin->q_height = 256; h = grawin.q_height; grwin->q_x = LEFT_EDGE; x = grawin.q_x; grwin->q_y = 0; y = grawin.q_y; sd_clear(to_grwn,-1); sd_clear(stderr,-1); /* read header information */ printf("\nReading Header information\n - - - \n\n"); read_pbm_header(fp_in); printf("\nplease wait - - reading bytes\n"); /* read image into 1 dimensional array */ img_bytes = fread(in_image, sizeof(unsigned char),(width *height)/8,fp_in); fclose(fp_in); printf(" %d img_bytes\n\n",img_bytes); printf("touch [space-bar]\n"); getch(); sd_clear(to_grwn,-1); /* density == bits set per image */ count = hite_count = wite_count= 0; /* set size of block for pixelating */ block = 1; grwin->q_width = block; w = grawin.q_width; grwin->q_height = block; h = grawin.q_height; for (byte_count=0; byte_count 127) { img_byte -= 128; grwin->q_x = LEFT_EDGE + wite_count; grwin->q_y = hite_count; x = grawin.q_x; y = grawin.q_y; sd_fill(to_grwn,-1,0,grwin); count++; } img_byte <<= 1; wite_count++; if(wite_count == width) { wite_count = 0; hite_count++; } } } getch(); /* hang on until we see it */ grwin->q_width = 512; w = grawin.q_width; grwin->q_height = 256; h = grawin.q_height; grwin->q_x = 0; x = grawin.q_x; grwin->q_y = 0; y = grawin.q_y; sd_setin(to_grwn,-1,0); sd_tab(to_grwn,-1,48); count -= 96; /* take out guide boxes */ printf("count = %d\n",count); sd_tab(to_grwn,-1,48); printf("last x = %d\n",wite_count); sd_tab(to_grwn,-1,48); printf("last y = %d\n",hite_count); sd_tab(to_grwn,-1,48); printf("width = %d\n",width); sd_tab(to_grwn,-1,48); printf("%d/%d = \n",(100*count),IMAGE_DOTS); sd_tab(to_grwn,-1,48); printf("%d with\n",(100*count)/IMAGE_DOTS); ort = (100*count) % IMAGE_DOTS; sd_tab(to_grwn,-1,48); printf("%d left over\n",ort); ort = ort*100; ort = ort/IMAGE_DOTS; getch(); sd_tab(to_grwn,-1,48); sd_tab(to_grwn,-1,48); printf("density:\n"); sd_tab(to_grwn,-1,48); sd_tab(to_grwn,-1,48); printf("%3d.%2d %%\n",((100*count)/(IMAGE_DOTS)),ort); printf("\n\n"); sd_tab(to_grwn,-1,48); printf(" [space-bar]\n"); sd_tab(to_grwn,-1,48); printf(" to leave\n"); getch(); fclose(fp_grwn); exit(0); } read_pbm_header(fp) FILE *fp; { int c, c1, file_type; c = getc(fp); c1 = getc(fp); if(c != 'P' || c1 != '4') { printf("PBM error: unsupported format.\n"); printf("must be bitmapped black/white.\n"); getch(); exit(1); } img_type[0]=c; img_type[1]=c1; img_type[3]='\0'; printf("image type: %s\n",img_type); width = getint(fp); printf("%d wide\n",width); height= getint(fp); printf("%d high\n",height); return( c1 - '0'); } int getint(fp) /* from John Bradley's */ FILE *fp; /* xv version 2.00 */ { /* as of 02/01/92 */ int c, i; int garbage, numgot=0; /* skip ahead */ c = getc(fp); while(1) { /* comments ? */ if (c == '#'){ /* found a comment */ printf("#"); while(c != '\n' && c != EOF) { c = getc(fp); printf("%c",c); } } if (c == EOF){ return 0; } if ( c >='0' && c <= '9') break; /* found a number */ if ( c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ',') garbage = 1; c = getc(fp); } /* go until non-number */ i = 0; while(1){ i = (i*10) + (c - '0'); c = getc(fp); if ( c == EOF) return i; if ( c < '0' || c > '9') break; } numgot++; return i; } itoab(n, s, b) /* convert integer to string in base b */ int n; char *s; int b; { char *ptr; int lowbit; ptr = s; b >>= 1; do { lowbit = n & 1; n = ( n >> 1 ) & INT_MAX; *ptr = ((n%b) << 1) + lowbit; if( *ptr <10) *ptr += '0'; else *ptr += 55; ++ptr; } while (n /= b); *ptr = 0; reverse (s); } reverse(s) /* reverse string in place */ char *s; { char *j; int c; j=s+strlen(s) -1; while(s < j) { c = *s; *s++ = *j; *j-- = c; } } itoa(n,s) /* convert int n to string s */ char *s; int n; { int sign; char *ptr; ptr = s; if((sign=n)<0) n= -n; do{ *ptr++ = n % 10 + '0'; } while (( n = n / 10) > 0); if ( sign <0) *ptr++ = '-'; *ptr = '\0'; reverse(s); } /* end of pbmtoql2C_c June 3, 1992 11:45 */