---------------- Documentation for OUT output package ----------------- This file should be MC:KSC;?OUT > or [SRI-NIC]OUT.DOC Contents: Brief usage summary Basic intro to OUT OUT items Miscellaneous cautions etc. Conversion: How to convert old FWRITE/UUOs stuff to OUT. NOTE: the OUT package is often in a state of development, and this documentation may not accurately reflect actual features. Normally, however, anything that used to work should continue to work unless otherwise noted. Comments & suggestions welcomed! Usage: .INSRT KSC;OUT or .INSRT OUT ; to invoke package Syntax: OUT(chan,func(args),(" Literal string "),func(args)...) chan - channel to output these items on. func(args) - function-like "item" that usually outputs its args. Basic channel types: OUT(ch,OPEN) ; Initialize for a "real" ITS channel OUT(ch,OPEN(UC$IOT,[jfn]) ; Ditto on TNX OUT(ch,OPEN(UC$BPT,[bp],[lim])) ; Writes up to chars using Basic items: ("Literal string") D([num]) ; outputs number in decimal O([num]) ; outputs number in octal F([num]) ; outputs number as floating-point. S([# bytes],[bp]) ; Outputs byte string TZ([asciz]) ; Outputs ASCIZ string General description: These are macros and routines supporting a new output package interface, OUT, which is the successor to FWRITE. The basic idea is quite similar, but the syntax of the invoking macro is different and much more flexible. The intent is to make the OUT macro and supporting routines efficient enough and general enough that no other means of output should be necessary. In particular, none of the individual "item" types should ever be invoked other than via OUT, and use of output UUO's or "direct" system output calls should be avoided. STANDARD OUTPUT: One important concept to remember is that there is always a "current output channel", or "standard output", identified by accumulator "OC". All output, by any means whatever, always goes to the standard output! If no channel argument is given to the OUT, output simply defaults to this standard output, which is quite efficient. When a channel argument IS given, OUT will set the standard output to this new channel, but always restores the previous value at the end of the call; thus OUT never permanently alters the value of OC. The only exception to this is the construct OUT(,CH(chan)) which explicitly requests that the standard output be set to . The channel number should normally be within the range 0 to 17 inclusive; this is a default rather than a real limitation since the range can be increased at assembly time. OUT "ITEMS": Within an OUT call, any reasonable number of "items" or "literal strings" may be specified. (Currently the definition of reasonable is about 16). A literal string is simply a STRUNG-type string enclosed in parentheses; an item consists of an item name, which may or may not have arguments associated with it. If arguments are given, they must be enclosed in parentheses immediately after the item name. The number of arguments an item takes depends on the particular item (some take a variable number). It is one exemplary feature of the OUT macro that furnishing too few or too many arguments will only affect that particular item; it will never destroy the overall functioning of the OUT call. Examples: OUT(TYOC,("This is example "),D(CNT),(" of"),D(TOT,5),EOL) The use of literal strings should be obvious. TYOC - During execution of this OUT, the standard output will be temporarily set to TYOC. D(CNT) - outputs the value at CNT in decimal. D(TOT,5) - outputs the value at TOT in decimal, right adjusting it within a 5-column field. This is an example of how some items can take more than one argument. EOL - simply outputs a CRLF. This demonstrates an item with no arguments at all. !!!!! CAVEAT !!!!!! In order to provoke the right behavior from MIDAS, OUT must be a "parenthesized call"; a "<", "(", or "[" must come immediately after the OUT with no intervening space. There is no "free format"; blanks or CRLFs between items will screw the stupid macro parser. Fixing this would require some changes to MIDAS. Under the covers: OUT can assemble in two basic ways; each of these can be specifically requested by using the names OUTCOD or OUTCAL instead of "OUT". OUT for default (normally OUTCOD) OUTCOD forces "inline" assembly OUTCAL forces single instruction CALL OUTCOD - In-line code PUSH P,OC ; Or nothing if std output MOVEI OC,CH ; Or nothing if std output POP P,OC ; Or nothing if std output OUTCAL - In-line call PUSHJ P,[HRLM OC,(P) ; Or nothing if std output MOVEI OC,CH ; Or nothing if std output HLRZ OC,(P) ; Or nothing if std output POPJ P, ] OUTCOD is the default and is used to get fast inline code, especially when using standard output. OUTCAL has the overhead of a PUSHJ/POPJ, but has the feature of being both skippable and XCT-able, and lends itself to constants optimization, again especially when using standard output. General policy should be to use OUT for everything except where a one-instruction invocation is specifically needed; for these, use OUTCAL. The OUTCAL invocation should not be used for any other reason, in order to clearly identify such places. Similarly, OUTCOD should only be used where it is essential that the code produced be inline. There is no preference implied for one or the other form of OUT invocation; this merely makes sure that nothing will break if the default form used by OUT is changed. Channel Opening, types, & manipulation: OPEN(itype,aval,alim,abytsize) Open a channel. This does NOT imply that the "hard" channel is likewise opened from the OS viewpoint; that must be done by user. abytsize - byte size, only used by UC$BUF. alim - # bytes maximum to output. Defaults to infinity. Attempts to output more will be no-ops. Note: In some cases, using FMT item truncation is simpler. Note: UC$BUF uses different interpretation. itype - as below. Defaults to UC$IOT. UC$IOT - "Hard" OS-opened output channel. aval - [jfn #], on TNX only. eg: OUT(tyoc,OPEN(UC$IOT,[.priou])) on TNX. UC$BUF - Ditto but buffered. aval - as for IOT. alim - buffer to use. If positive, a buffer of that many BYTES is allocated. Zero or default allocates one page's worth. If negative, is taken as AOBJN -<# wds>,, abytsize - byte size to use. Defaults to 7 (standard ASCII) eg: OUT(bc,OPEN(UC$BUF,,[-bflen,,buff])) UC$BPT - Byte pointer. aval - BP to output with. eg: OUT(bpc,OPEN(UC$BPT,[440700,,stuff])) UC$UAR - UUO Area. aval = ARPT to specific area. eg: OUT(ac,OPEN(UC$UAR,omfar)) UC$NUL - Null output sink. UC$SAO - with UUO LISTS, like SAOBEG. aval - pointer to LSE (defaults to current LSE) eg: OUT(lc,OPEN(UC$SAO,$arloc+msgar)) UC$XCT - XCT operation aval - Instr to XCT (takes byte in U1, chan in OC) eg: OUT(xc,OPEN(UC$XCT,[call hacko])) UC$TRN - TRANslated channel aval - channel # to translate output to. Ignores "alim". eg: OUT(dtyoc,OPEN(UC$TRN,[tyoc])) FRC Force out all buffered output. No-op for anything but a UC$BUF type channel. CLS Close the channel. Implies FRC. Unlike OPEN, this actually WILL effect closure of the "hard" channel to the OS. PTV(aret) Returns pointer-value for channel. Generally speaking this tries to be the # of bytes output on the channel since it was opened, but for certain channel types this may be different: BUF - # of bytes currently in buffer. UAR - # of chars in whole area (between beg and $ARWPT) TRN - value for translated channel. CH(ichan) Set standard output to channel specified. This will not last beyond the current OUT invocation unless no channel was specified to the OUT, i.e. the default std output is in use. eg: OUT(,CH(chan)) does the right thing. FMT(ITEM,iwid,iprec,ifill) Hairy field formatting output. Outputs ITEM (can be any item, with args) according to formatting parameters: iwid - Field width in columns. If positive, output is right justified. If negative, output is left justified. Output is never truncated by this parameter. Defaults to zero (no justification) iprec - "precision"; max # of chars to output. This parameter DOES truncate output!! Truncation happens before justification. Defaults to infinity. ifill - "fill character" to use as justification padding. Defaults to blank. LIST OF OUT ITEMS: The following terminology will be used in describing OUT items and the arguments they take: ITEM(ixxx,axxx,{opt1,opt2}...) ITEM - name of item {...} - args in braces are optional. ixxx - "immediate" arg, MOVEI'd. xxx is rest of arg name. axxx - "addressed" arg, MOVE'd. xxx is rest of arg name. Common names: abp - address of a byte pointer. acnt - address of a count. aval - address of a value (implied numerical) a6 - address of a sixbit word. C(ich) Character. Outputs single byte (since this is MOVEI'd it only goes up to 18 bits). ; W(aval) Word. Outputs single byte (MOVE'd, so can be up to 36 bits). ; or B(aval) Byte. ; Not implemented yet; just listed for consideration. S(acnt,abp) String. Outputs cnt bytes from source bp. TS(astr) String variable. Address of [,,cnt ? bp] TA(arpt) Area. Address is of an ARBLK for an area. TZ(asciz) ASCIZ. Address is of an ASCIZ string. TZ$(aasciz) ASCIZ, RH of value is address of ASCIZ. A bit crockish. TC(ascnt) ASCNT. Address is of [cnt,,[ascii /str/]] TPZ(abp) BYTEZ. Outputs from bp until zero byte. TPC(acrock) Ugh. Address is of [cnt,,[bp]]. Obsoleted by "S". $$OHST items: ---------------------------------------- HN(aval) Host number. Outputs value as octal host #, simplifying if possible. HND(aval) Like HN but decimal Internet address format. HST(aval) Host name. If no name for given number, becomes "HND". $$OERR item: ---------------------------------------- ERR({aerr}) Outputs error message for given error # from system. If none specified, or value is -1, outputs message for last error encountered by program, e.g. as in OUT(,ERR). SIMPLE items: --------------------------------------- CRLF Outputs a CR and LF. EOL End-of-Line, same as CRLF. TAB Outputs a TAB char SP Outputs a space char LPAR,RPAR Parentheses, (Left and Right) LBRK,RBRK Brackets, [Left and Right] LBRC,RBRC Braces, {Left and Right} LABR,RABR Angle-brackets, SIXBIT output: ------------------------------------------- 6W(a6) 6-bit word, all 6 chars. 6F(a6) 6-bit "Filename" - no trailing blanks 6Q(a6) 6-bit Quoted filename - Like 6F, but certain chars special in a filename are quoted with ^Q. These chars are anything not alphanumeric or "-". NUMERICAL OUTPUT: ---------------------------------------------- D(aval,{ifld}) Decimal output O(aval,{ifld}) Octal X(aval,{ifld}) Hexadecimal aval - number to output ifld - width of the field to output in. If positive, string will be right justified. If negative, string will be left justified. Output will never be truncated by this parameter. RH(aval) RH as oooooo (6 octal digits) LH(aval) LH similar. H(aval) Halfword as LH,,RH RHV(aval) RH as positive octal value LHV(aval) Similar HV(aval) Similar RHS(aval) RH as Signed octal number (i.e. sign extension) LHS(aval) Similar HS(aval) Similar $$OFLT Floating-point Output: -------------------------------------- F(aval,{ifld,iprec}) Floating-point "F" - mmm.nnn E(aval,{ifld,iprec}) Floating-point "E" - m.nnnnnnE+ee G(aval,{ifld,iprec}) Floating-point "G" - F or E as appropriate. aval, ifld - as for D,O,X iprec - Precision. Specifies # of digits to right of the decimal point. $$OTIM Time Output items: -------------------------------------- ; All of these take an optional time-word argument. ; If this is not specified, the current time is used. TIM(HMS,{atim}) Time as "hh:mm:ss" TIM(MDY,{atim}) Date as "mm/dd/yy" TIM(YMD,{atim}) Date as "yymmdd" TIM(MDYT,{atim}) Datime as "mm/dd/yy hh:mm:ss" TIM(MONTH,{atim}) Month as "Month" TIM(MON,{atim}) Month as "MON" TIM(DOW,{atim}) Day of week as "Fooday" TIM(DOW3,{atim}) Day of week as "Foo" TIM(F1,{atim}) Datime as "dd MON yy hhmm ZON" TIM(F2,{atim}) Datime as "dd Month yyyy hh:mm ZON" TIM(F3,{atim}) Datime as "dd MON yy hhmm-ZON" TIM(RFC1,{atime}) Datime as RFC822 "dd Mon yy hh:mm:ss ZON" TIM(RFC2,{atime}) Datime as RFC822 (RFC1) but with short DOW. DEFINING NEW "OUT" ITEMS: Pick some item name of 4 chars or less. Then set up the following definitions: DEFINE OUT"$! (ARG1,ARG2,...) ; Args !! MUST BE BALANCED !!! > TERMIN OX!: RET ; To return when done. The code must "never" leave OC altered. (exceptions to this should be left to package-internal routines). Note that U2 may be = to OC, so it is good form to avoid using U2 unless saving/restoring is better than using just 3 ACs. Note also the common convention (though not restriction) that direct calls pass a single arg in U3. Other than this, ACs U1-U4 are freely available. Actual output mechanism: Within the code for an output item, there are two fundamental ways to output stuff: Byte: STDOUT - outputs byte in U1 over channel in OC. No ACs are clobbered. STDOUT(arg) - same but does MOVEI U1,arg prior to STDOUT. This saves some coding. Note arg is balanced, so beware of commas or single bracket-chars!!! STDOBP - Same as STDOUT, but assumes that a byte ptr is in U3 and takes care to preserve it should an area-shift happen as a result of the output. Thus U3 may change. String: ; This is how to do string output MOVE U3,[byte ptr] ; U3 takes byte pointer SKIPLE U4,[# of bytes] ; U4 takes # bytes (must be positive!) CALL @USCOPT(OC) ; Invoke string output for channel! ; All of U1, U3, U4 and U2 (if != OC) ; may be clobbered. WRITING "XCT" CHANNEL CODE: (This stuff currently only talks about existing XCT facility, which is slated for flavorful expansion) The argument to the OPEN should be a single instruction which outputs the byte in U1. The channel # is available in OC. Usually this will have to be a CALL to some routine, and the following conditions hold: No ACs should be clobbered!! This includes U1 and OC. In future, arg will be a pointer to a vector block which specifies all the goodies such as string-mode dispatch, overflow dispatch, etc. as well as the unit-mode instruction. ------------------------------------------------------------------------ CONVERSION OF OLD FWRITE/UUOS CODE: The original intent was that all programs which still used FWRITE/UUOS for output would continue to work without modification. This was true for a long time but was changed in order to better modularize packages. Thus, old software that used to depend on NUUOS and FWRITE alone may not assemble properly without the following addition: $$OUUO==1 ; This must be defined prior to the .INSRT of NUUOS That should be all that is needed to ensure that such programs continue to work. Of course, if they make unwarranted use of any UUO package internals, they may require some checking. The following discussion explains how to convert old programs (if there are any left) on the assumption that this will always be desirable. Steps to convert ancient NUUOS-only software: (0) Set $$OUUO==1 and resolve undefined symbols. Because output-related functions have been moved to the OUT package, any references to symbols defined therein will now fail, unless OUT" is prefixed to these references. This is a deliberate incompatibility to help flush out such refs and tag them for easy future checking. (1) Check out any UUO definitions. Programs which define their own UUO's will need some checking to make sure they conform to standards described in the UUO documentation (MC:KSC;?UUOS > on ITS). If no UUO's are defined, you already win. (2) Verify operation. No other changes to the sources should be necessary, provided steps (0) and (1) have been satisfied. It is remotely possible that certain FWRITEs will not work, because the FWRITE macro no longer expands into UUOs. However, the new code should have exactly the same results. Code which assumes that FWRITE assembles into a single instruction (and tries to skip over it) will lose grossly, but DESERVEs to lose because the doc has always said not to try that. Now the new OUT macro is included and can be used in place of or in combination with FWRITE. Since it incorporates new item types, is cleaner, and faster, its use is preferable for new output statements. Its only disadvantage is that it is slightly more painful to set up literal strings; however, improvements to MIDAS macro parsing may fix this someday. (3) Set things up for removal of the $$OUUO==1. This switch controls inclusion of the old output UUOs, including OUTOPN and OUTPTV. It defaults to 0, which will DISABLE all output UUOs!! This is the most significant conversion step since you have to be sure that none of these UUO's remain in the source; all should have been converted to use OUT by then. Since FWRITE still works, this primarily means that any code which directly invokes these UUO's should be changed. The main advantage is that they no longer gobble up most of the space in the UUO table, so that you can use the entries for more useful purposes. (4) ?? Replace instances of FWRITE? It is intended that FWRITE will continue to work under the new OUT package, although it will not be further developed; only OUT will have new features. At some point in the future, it may be that all programs will have abandoned the use of FWRITE, which can then be flushed or recycled. MAKSTR and CONC will be given OUT-style constructions as well.