As a second example of working with files, we present a companion to the SORTSTR program, which performed a bubble sort on strings entered interactively. The SORTINT program (Figure 9-6) reads integer quantities from an ASCII text file into internal binary storage as quad words, sorts them using the bubble sort algorithm, and writes the ordered list of signed integers to a new text file, one per line. This program utilizes I/O features of the SCANFILE program to implement the bubble algorithm of the SORTSTR program. Figure 9-6 SORTINT: Bubble sort for integer quantities// SORTINT Bubble sort integers from a file // This program will read 100 or fewer integers from a // text file, sort them using the bubble sort algorithm, // and write the sorted list into a text file. FLEN = 40 // File name allowance CASES = 100 // Array length NUML = 8 // Integer size .global gets, perror, printf .global fopen, fclose, fscanf, fprintf .data // Declare storage .align 8 // Desired alignment ARRAY: .skip CASES*NUML // Room for integers IFILE: .skip FLEN // Input file name OFILE: .skip FLEN // Output file name IPRMT: stringz "Input from? " OPRMT: stringz "Output to? " IMODE: stringz "r" // Read from input file OMODE: stringz "w" // Create output file TELL: stringz "The program has processed %d numbers.\n" PFORM: stringz "%s" // Prompts are strings IFORM: stringz "%lld" // Scan for a "word" OFORM: stringz "%18lld\n" // Print number & newline ERROR: stringz "Error" .text // Section for code .align 32 // Desired alignment .global main // These three lines .proc main // mark the mandatory main: // 'main' program entry .prologue 12,r32 // Mask for rp, ar.pfs only alloc loc0 = ar.pfs,0,8,3,0 // ins, locals, outs .save rp,loc1 // Must save return address mov loc1 = b0;; // to our caller .body first: add out0 = @gprel(IPRMT),gp // out0 -> format mov loc2 = gp // Save gp br.call.sptk.many b0 = printf // Ask about input mov gp = loc2 // Restore gp cmp4.lt p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop0;; // go to handler (null) add out0 = @gprel(IFILE),gp // out0 -> filename br.call.sptk.many b0 = gets // Unformatted input mov gp = loc2 // Restore gp cmp.eq p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop1;; // go to handler (null) add out0 = @gprel(IFILE),gp // out0 -> filename add out1 = @gprel(IMODE),gp // out1 -> mode br.call.sptk.many b0 = fopen // Find input file mov gp = loc2 // Restore gp cmp.eq p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop2;; // go to handler (null) mov loc3 = r8 // loc3 = file pointer add out0 = @gprel(OPRMT),gp // out0 -> format br.call.sptk.many b0 = printf // Ask about input mov gp = loc2 // Restore gp cmp4.lt p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop0;; // go to handler (null) add out0 = @gprel(OFILE),gp // out0 -> filename br.call.sptk.many b0 = gets // Unformatted input mov gp = loc2 // Restore gp cmp.eq p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop1;; // go to handler (null) add out0 = @gprel(OFILE),gp // out0 -> filename add out1 = @gprel(OMODE),gp // out1 -> mode br.call.sptk.many b0 = fopen // Find output file mov gp = loc2 // Restore gp cmp.eq p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop4;; // go to handler (null) mov loc4 = ret0 // loc4 = file pointer mov loc5 = 0 // loc5 counts numbers add loc6 = @gprel(ARRAY),gp;; // loc6 -> buffer loop: mov out0 = loc3 // out0 = IPTR add out1 = @gprel(IFORM),gp // out1 -> format mov out2 = loc6 // out2 -> ARRAY br.call.sptk.many b0 = fscanf // Read a number mov gp = loc2 // Restore gp cmp4.ne p6,p0 = 1,ret0 // Expect one %d item (p6) br.cond.sptk.few eof;; // No - maybe it's EOF add loc6 = NUML,loc6 // Bump storage pointer add loc5 = 1,loc5;; // Count one number cmp.gt p6,p0 = CASES,loc5 // If storage is ok, (p6) br.cond.sptk.few loop;; // go back for more eof: cmp4.ne p6,p0 = -1,ret0 // If not EOF, (p6) br.cond.sptk.few stop6;; // then exit mov out0 = loc3 // out0 = input pointer br.call.sptk.many b0 = fclose // Close input mov gp = loc2 // Restore gp cmp4.ne p6,p0 = 0,ret0 // If not successful, (p6) br.cond.sptk.few stop3;; // then exit sort: add r20 = -1,loc5;; // r20 = outer count-down o_loop: mov r21 = r20 // r21 = inner count-down add r20 = -1,r20 // Count down for o_loop add r22 = @gprel(ARRAY),gp;; // r22 -> 1st add r23 = NUML,r22;; // r23 -> 2nd number i_loop: mov r2 = r22 // r2 -> 1st number (temp) mov r3 = r23;; // r3 -> 2nd number (temp) add r21 = -1,r21;; // Count down for i_loop look: ld8 r24 = [r2] // r24 = 1st number ld8 r25 = [r3];; // r25 = 2nd number why: cmp.le p6,p0 = r24,r25 // If 1,2 order is ok, (p6) br.cond.spnt.many adjust;; // go on to next numbers swap: st8 [r2] = r25 // Swap the data st8 [r3] = r24 // between the locations adjust: add r22 = NUML,r22 // Advance to next 1st add r23 = NUML,r23 // Advance to next 2nd cmp.gt p6,p0 = r21,r0 // Still more work (p6) br.cond.sptk.many i_loop;; // for inner loop to do? cmp.gt p6,p0 = r20,r0 // Still more work (p6) br.cond.sptk.many o_loop // for outer loop to do? add loc6 = @gprel(ARRAY),gp // loc6 -> ARRAY mov loc7 = loc5;; // Copy of the count p_loop: mov out0 = loc4 // out0 = output pointer add out1 = @gprel(OFORM),gp // out1 -> format ld8 out2 = [loc6],NUML // out2 = what to print add loc7 = -1,loc7 // Count down for p_loop br.call.sptk.many b0 = fprintf // C print function mov gp = loc2 // Restore gp cmp4.lt p6,p0 = ret0,r0 // If any error, (p6) br.cond.sptk.few stop7;; // go to handler (null) cmp.gt p6,p0 = loc7,r0 // Still more work (p6) br.cond.sptk.few p_loop // for print loop to do? mov out0 = loc4 // out0 = OPTR br.call.sptk.many b0 = fclose // Close output mov gp = loc2 // Restore gp cmp4.ne p6,p0 = 0,ret0 // If not successful, (p6) br.cond.sptk.few stop5;; // then exit add out0 = @gprel(TELL),gp // out0 -> format mov out1 = loc5 // out1 = number of words br.call.sptk.many b0 = printf // C print function mov gp = loc2 // Restore gp cmp4.lt p6,p0 = r8,r0 // If any error, (p6) br.cond.sptk.few stop0;; // go to handler (null) br.cond.sptk.many done // That is all stop0: // Terminal output error stop1: // Terminal input error stop2: // Problem opening IFILE stop3: // Problem closing IFILE stop4: // Problem opening OFILE stop5: // Problem closing OFILE stop6: // Problem getting input stop7: // Problem doing output add out0 = @gprel(ERROR),gp // out0 -> format br.call.sptk.many b0 = perror // C error function mov gp = loc2 // Restore gp done: mov ret0 = 0 // Signal all is normal mov b0 = loc1 // Restore return address mov ar.pfs = loc0 // Restore caller's ar.pfs br.ret.sptk.many b0;; // Back to command line .endp main // Mark end of procedure The fscanf function (using %lld as the format string) in the data input loop (starting at loop) expects an address for the location where the interpreted binary value is to be stored. In contrast, the fprintf function in the data output loop (starting at p_loop) expects an actual value as an argument in a stacked register or in a special area on the stack. The behavior of this program on a Linux system can be explored with both invalid and valid input, as follows: L> bin/sortint Input from? sortint.txt Output to? /abc.txt Error: Permission denied L> Input from? sortint.txt Output to? sorted.txt The program has processed 5 numbers. L> cat sorted.txt -20 2 24 123 200 L> cat sortint.txt 2 200 -20 123 24 L> Assuming that there is a file named sortint.txt in the current directory, the first error is a result of the user not having permission to create files in the root directory. On systems where native integers are 64 bits in width, ll can be used with numeric indicators (like %d) in format strings for I/O routines like fscanf and fprintf in the C support library when the quantities are anticipated to be negative ( 20 here) or positive but spilling beyond 32 bits in width. We have again suggested where some of the conditional tests for errors should be positioned. Just above done we have also shown how to use the perror function to display the error text, which may vary with the programming environment or default language on a particular system. |