.title format - Format a string UNIX style .ident "V02.00" ;+ ; Index Format a string UNIX style ; ; Usage ; ; length = format(buffer, format, arg1, ...); ; char *buffer; ; char *format; ; int length; ; ; Description ; ; format() converts and formats its arguments, under the control ; of the format string, into the buffer indicated in the first ; argument. ; ; The format string is a character string which contains two ; types of objects: plain characters, which are simply copied ; to the buffer, and conversion specifications, each of which ; cause conversion of the next successive argument. ; ; Each conversion specification is introduced by the % character. ; Following the %, there may be ; ; - an optional minus sign "-" which specifies left ; adjustment of the converted argument in the indicated ; field. ; ; - an optional digit string specifying field width; if ; the converted argument has fewer characters than the ; field width, it will be blank-padded on the left (or ; right, if the left-adjustment indicator has been ; given) to make up the field width. If the field ; width is specified as '*' or '?', the next argument ; is used. (Note: '?' is obsolete.) ; ; - an optional period "." which serves to separate the ; field width from the next digit string; ; ; - an optional digit string (precision) which specifies ; the number of digits to appear after the decimal ; point for e- and f-conversion, or the maximum number ; of characters to be printed from a string. If the ; precision is specified as '*' or '?', the next ; argument is used. ; ; - a character which indicates the type of conversion ; to be applied. ; ; The conversion characters and their meanings are ; ; d Signed-decimal ; u Unsigned-decimal ; o Octal ; X Hexadecimal, 10-15 are represented by A-F ; x Hexadecimal, 10-15 are represented by a-f ; ; The integer argument is converted to decimal, ; octal, or hexadecimal notation respectively. ; Any of the conversion characters may be ; preceeded by 'l' to signal "long" integer ; argument. Note that the Unix usage of capital ; letters to represent long arguments is not ; supported. ; ; c The argument character is printed. (Note that ; 'lc' takes a long integer argument.) ; ; r Remote format. The next printf() argument is ; the format. Note that this is not a subroutine. ; The current format is not processed further. For ; example: ; ; bug(args) ; { ; error("Error at %r", &args); ; } ; ; This routine might be called as follows: ; ; bug("Error %d at %s\n", val, name); ; ; s The argument is taken to be a string (character ; pointer) and characters from the string are ; printed until a null character or until the ; number of characters indicated by the precision ; specification is reached; however if the ; precision specification is 0 or missing all ; characters up to null are printed. ; ; If no recognizable character appears after the %, that character ; is printed; thus % may be printed by the use of the string %%. ; In no case does a non-existant or small field width cause truncation ; of a field; padding takes place only if the specified field ; width exceeds the actual width. ;- ; Edits: ; V02.00 19-Oct-82 TTC Rework of old CS library ; auto$$ = -6 ; See acsv.mac for the correct value spare = auto$$-2 ; Output function is fixed. ARGP = auto$$-4 LJUST = auto$$-6 PREC = auto$$-10 WIDE = auto$$-12 FILL = auto$$-14 HORD = auto$$-16 LORD = auto$$-20 BUF = auto$$-44 ; 20 bytes. OLDP = auto$$-46 STACK = 46 ; Last argument for stack get .psect c$strn null: .asciz "{Null}" .even .psect c$code format:: jsr r5,csv$ ;Save registers, etc. mov c$pmtr+0(r5),r4 ;r4 --> output buffer mov #c$pmtr+2,r0 ;r0 offset to format string address sub #STACK,sp ;Get stack area add r5,r0 ;r0 --> format address mov (r0)+,r3 ;r3 --> format mov r0,ARGP(r5) ;ARGP(r5) --> arg's. ; ; Get next character from the ; format string. ; If not a '%' just send it to the ; output. ; prf01: movb (r3)+,r0 bne 25$ jmp prf03 25$: cmp r0,#'% beq 30$ movb r0,(r4)+ br prf01 ; ; Get widths and flags. ; 30$: clr LJUST(r5) clr WIDE(r5) mov #-1,PREC(r5) mov #' ,FILL(r5) movb (r3)+,r0 cmp r0,#'- bne 40$ inc LJUST(r5) movb (r3)+,r0 40$: cmp r0,#'0 bne 50$ mov r0,FILL(r5) movb (r3)+,r0 50$: call num mov r1,WIDE(r5) cmp r0,#'. bne 60$ movb (r3)+,r0 call num mov r1,PREC(r5) ; ; %r Remote format ; 60$: cmp r0,#'r bne 90$ mov @ARGP(r5),ARGP(r5) mov @ARGP(r5),r3 add #2,ARGP(r5) br prf01 ; ; Get the data. If there is an 'l' in ; the format copy a long to HORD and ; LORD. Otherwise copy the integer to ; LORD and sign extend if %d. ; 90$: mov r5,r2 add #BUF,r2 mov ARGP(r5),OLDP(r5) mov @ARGP(r5),r1 add #2,ARGP(r5) cmp r0,#'l bne 100$ ; ; %l Long integer ; mov r1,HORD(r5) mov @ARGP(r5),LORD(r5) add #2,ARGP(r5) movb (r3)+,r0 br 120$ 100$: cmp r0,#'d beq 110$ mov r1,LORD(r5) clr HORD(r5) br 120$ 110$: clr HORD(r5) mov r1,LORD(r5) bpl 120$ com HORD(r5) ; ; %c Character ; 120$: cmp r0,#'c bne 130$ mov r5,r2 add #LORD,r2 clrb LORD+1(r5) br prf02 ; ; %s String ; ; If pointer is 0, print {Null} ; 130$: cmp r0,#'s bne 140$ mov LORD(r5),r2 bne prf02 mov #null,r2 br prf02 ; ; %d, %o, %u, %x, %X Integer conversion ; ; Only %d gets integers sign extended. ; All done with common routine. ; 140$: cmp r0,#'d beq 150$ cmp r0,#'o beq 150$ cmp r0,#'u beq 150$ cmp r0,#'x beq 150$ cmp r0,#'X bne 160$ 150$: mov LORD(r5),-(sp) mov HORD(r5),-(sp) mov r0,-(sp) mov r2,-(sp) call $$ltoa add #10,sp br prf02 ; ; None of the above. ; Restore ARGP so an argument is not ; eaten. ; 160$: mov OLDP(r5),ARGP(r5) movb r0,(r4)+ jmp prf01 ; ; Send out the null terminated ascii ; string pointed to by r2. ; Inserted any required fills and ; pads. ; prf02: mov r2,r1 170$: tstb (r1)+ bne 170$ dec r1 sub r2,r1 tst PREC(r5) bmi 180$ cmp PREC(r5),r1 bhis 180$ mov PREC(r5),r1 180$: mov r1,PREC(r5) tst LJUST(r5) bne 190$ call fills 190$: mov PREC(r5),r1 200$: dec r1 bmi 210$ movb (r2)+,r0 movb r0,(r4)+ br 200$ 210$: tst LJUST(r5) beq 215$ call fills 215$: jmp prf01 ; ; All done. Append the null byte, compute and return ; the null byte. ; prf03: clrb (r4) sub C$PMTR+0(r5),r4 ; r4 = length mov r4,r0 ; Return it jmp cret$ ; ; Output WIDE - PREC copies of the ; FILL character. ; fills: mov WIDE(r5),r1 sub PREC(r5),r1 ble 240$ mov FILL(r5),r0 230$: movb r0,(r4)+ dec r1 bne 230$ 240$: return ; ; Read in a field width. ; The first character of the width is ; in r0. ; The width is returned in r1. ; If the width specifier is '*' or '?' then the ; width is obtained from the args. ; num: cmp r0,#'* beq 10$ cmp r0,#'? bne 250$ 10$: mov @ARGP(r5),r1 add #2,ARGP(r5) movb (r3)+,r0 br 270$ 250$: clr r1 260$: cmp r0,#'0 blo 270$ cmp r0,#'9 bhi 270$ asl r1 mov r1,-(sp) asl r1 asl r1 add (sp)+,r1 add r0,r1 sub #'0,r1 movb (r3)+,r0 br 260$ 270$: return .end