// USEFGETS     Demonstrate I/O for terminal (fgets)

// This adaptation of SCANTERM uses fgets instead of
// gets. (Stop it with CTRL/C.)
// (Need -x assembler-with-cpp in Linux/gcc command line)
        IBUFL   = 256             // Input allowance
        SPACE   = 0x20            // ASCII code for 
        NL      = 0xa             // Newline code
        .global fgets, puts, printf
        .data                     // Declare storage
        .align  8                 // Desirable alignment
IBUF:   .skip   IBUFL             // Input line
PRMT:   stringz "Enter a line of text (CTRL/C to quit)"
TELL:   stringz "Found %d words containing %d characters.\n"
         .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,4,3,0  // ins, locals, outs
        .save   rp,loc1           // Must save return address
        mov     loc1 = b0;;       //  to our caller
        .body
        mov     loc2 = gp         // Save gp
line:   add     out0 = @gprel(PRMT),r1  // out0 -> prompt
        br.call.sptk.many b0 = puts  // Unformatted output
        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(IBUF),r1  // out0 -> buffer
        mov     out1 = IBUFL            // out1 = buffer size
#ifdef  __HP_cc      
        .global __iob             // HP-UX operating system?
        add     r2 = @ltoff(__iob),r1;; // Find file pointer
        ld8     r3 = [r2];;             //  corresponding to
        mov     out2 = r3               //   stdin
#else                
        .global stdin             // Linux operating system?
        add     r2 = @ltoff(stdin),r1;; // Find file pointer
        ld8     r3 = [r2];;             //  corresponding to
        ld8     out2 = [r3]             //   stdin
#endif                            // End of conditional block
        br.call.sptk.many b0 = fgets  // Unformatted input
        mov     gp = loc2         // Restore gp
        cmp.eq  p6,p0 = r8,r0     // If any error,
   (p6) br.cond.sptk.few stop1;;  //  go to handler (null)
first:  mov     r20 = 0           // Gr20 = character count
        mov     r21 = 0           // Gr21 = word count
        addl	r14 = @gprel(IBUF),gp;; // Gr14 --> input
next:   ld1     r22 = [r14],1;;   // Get a character; bump
        cmp.eq  p7,p8 = SPACE,r22 // End of word?
        cmp.eq  p6,p0 = NL,r22    // Newline code marks end
   (p6) br.cond.spnt.few nomore;; //  of our work here
   (p8) add     r20 = 0x1,r20     // No: count a character
   (p7) add     r21 = 0x1,r21     // Yes: count a word
        br.cond.sptk.few next     // Go back for more
nomore: add     r21 = 0x1,r21     // The last word
        add     out0 = @gprel(TELL),r1;;  // out0 -> format
        mov     out1 = r21        // out1 = number of words
        mov     out2 = r20        // out2 = number of chars
        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 line    // Look for another line?
stop0:                            // Output error
stop1:                            // EOF or input error
done:   mov     ret0 = r0         // 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