September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
|
|
@ -0,0 +1,331 @@
|
|||
OPTION COMPARE BINARY
|
||||
OPTION EXPLICIT ON
|
||||
OPTION INFER ON
|
||||
OPTION STRICT ON
|
||||
|
||||
IMPORTS SYSTEM.GLOBALIZATION
|
||||
IMPORTS SYSTEM.TEXT
|
||||
IMPORTS SYSTEM.RUNTIME.INTEROPSERVICES
|
||||
IMPORTS SYSTEM.RUNTIME.COMPILERSERVICES
|
||||
|
||||
MODULE ARGHELPER
|
||||
READONLY _ARGDICT AS NEW DICTIONARY(OF STRING, STRING)()
|
||||
|
||||
DELEGATE FUNCTION TRYPARSE(OF T, TRESULT)(VALUE AS T, <OUT> BYREF RESULT AS TRESULT) AS BOOLEAN
|
||||
|
||||
SUB INITIALIZEARGUMENTS(ARGS AS STRING())
|
||||
FOR EACH ITEM IN ARGS
|
||||
ITEM = ITEM.TOUPPERINVARIANT()
|
||||
|
||||
IF ITEM.LENGTH > 0 ANDALSO ITEM(0) <> """"C THEN
|
||||
DIM COLONPOS = ITEM.INDEXOF(":"C, STRINGCOMPARISON.ORDINAL)
|
||||
|
||||
IF COLONPOS <> -1 THEN
|
||||
' SPLIT ARGUMENTS WITH COLUMNS INTO KEY(PART BEFORE COLON) / VALUE(PART AFTER COLON) PAIRS.
|
||||
_ARGDICT.ADD(ITEM.SUBSTRING(0, COLONPOS), ITEM.SUBSTRING(COLONPOS + 1, ITEM.LENGTH - COLONPOS - 1))
|
||||
END IF
|
||||
END IF
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
SUB FROMARGUMENT(OF T)(
|
||||
KEY AS STRING,
|
||||
<OUT> BYREF VAR AS T,
|
||||
GETDEFAULT AS FUNC(OF T),
|
||||
TRYPARSE AS TRYPARSE(OF STRING, T),
|
||||
OPTIONAL VALIDATE AS PREDICATE(OF T) = NOTHING)
|
||||
|
||||
DIM VALUE AS STRING = NOTHING
|
||||
IF _ARGDICT.TRYGETVALUE(KEY.TOUPPERINVARIANT(), VALUE) THEN
|
||||
IF NOT (TRYPARSE(VALUE, VAR) ANDALSO (VALIDATE IS NOTHING ORELSE VALIDATE(VAR))) THEN
|
||||
CONSOLE.WRITELINE($"INVALID VALUE FOR {KEY}: {VALUE}")
|
||||
ENVIRONMENT.EXIT(-1)
|
||||
END IF
|
||||
ELSE
|
||||
VAR = GETDEFAULT()
|
||||
END IF
|
||||
END SUB
|
||||
END MODULE
|
||||
|
||||
MODULE PROGRAM
|
||||
SUB MAIN(ARGS AS STRING())
|
||||
DIM DT AS DATE
|
||||
DIM COLUMNS, ROWS, MONTHSPERROW AS INTEGER
|
||||
DIM VERTSTRETCH, HORIZSTRETCH, RESIZEWINDOW AS BOOLEAN
|
||||
|
||||
INITIALIZEARGUMENTS(ARGS)
|
||||
FROMARGUMENT("DATE", DT, FUNCTION() NEW DATE(1969, 1, 1), ADDRESSOF DATE.TRYPARSE)
|
||||
FROMARGUMENT("COLS", COLUMNS, FUNCTION() 80, ADDRESSOF INTEGER.TRYPARSE, FUNCTION(V) V >= 20)
|
||||
FROMARGUMENT("ROWS", ROWS, FUNCTION() 43, ADDRESSOF INTEGER.TRYPARSE, FUNCTION(V) V >= 0)
|
||||
FROMARGUMENT("MS/ROW", MONTHSPERROW, FUNCTION() 0, ADDRESSOF INTEGER.TRYPARSE, FUNCTION(V) V <= 12 ANDALSO V <= COLUMNS \ 20)
|
||||
FROMARGUMENT("VSTRETCH", VERTSTRETCH, FUNCTION() TRUE, ADDRESSOF BOOLEAN.TRYPARSE)
|
||||
FROMARGUMENT("HSTRETCH", HORIZSTRETCH, FUNCTION() TRUE, ADDRESSOF BOOLEAN.TRYPARSE)
|
||||
FROMARGUMENT("WSIZE", RESIZEWINDOW, FUNCTION() TRUE, ADDRESSOF BOOLEAN.TRYPARSE)
|
||||
|
||||
' THE SCROLL BAR IN COMMAND PROMPT SEEMS TO TAKE UP PART OF THE LAST COLUMN.
|
||||
IF RESIZEWINDOW THEN
|
||||
CONSOLE.WINDOWWIDTH = COLUMNS + 1
|
||||
CONSOLE.WINDOWHEIGHT = ROWS
|
||||
END IF
|
||||
|
||||
IF MONTHSPERROW < 1 THEN MONTHSPERROW = MATH.MAX(COLUMNS \ 22, 1)
|
||||
|
||||
FOR EACH ROW IN GETCALENDARROWS(DT:=DT, WIDTH:=COLUMNS, HEIGHT:=ROWS, MONTHSPERROW:=MONTHSPERROW, VERTSTRETCH:=VERTSTRETCH, HORIZSTRETCH:=HORIZSTRETCH)
|
||||
CONSOLE.WRITE(ROW)
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
ITERATOR FUNCTION GETCALENDARROWS(
|
||||
DT AS DATE,
|
||||
WIDTH AS INTEGER,
|
||||
HEIGHT AS INTEGER,
|
||||
MONTHSPERROW AS INTEGER,
|
||||
VERTSTRETCH AS BOOLEAN,
|
||||
HORIZSTRETCH AS BOOLEAN) AS IENUMERABLE(OF STRING)
|
||||
|
||||
DIM YEAR = DT.YEAR
|
||||
DIM CALENDARROWCOUNT AS INTEGER = CINT(MATH.CEILING(12 / MONTHSPERROW))
|
||||
' MAKE ROOM FOR THE THREE EMPTY LINES ON TOP.
|
||||
DIM MONTHGRIDHEIGHT AS INTEGER = HEIGHT - 3
|
||||
|
||||
YIELD "[SNOOPY]".PADCENTER(WIDTH) & ENVIRONMENT.NEWLINE
|
||||
YIELD YEAR.TOSTRING(CULTUREINFO.INVARIANTCULTURE).PADCENTER(WIDTH) & ENVIRONMENT.NEWLINE
|
||||
YIELD ENVIRONMENT.NEWLINE
|
||||
|
||||
DIM MONTH = 0
|
||||
DO WHILE MONTH < 12
|
||||
DIM ROWHIGHESTMONTH = MATH.MIN(MONTH + MONTHSPERROW, 12)
|
||||
|
||||
DIM CELLWIDTH = WIDTH \ MONTHSPERROW
|
||||
DIM CELLCONTENTWIDTH = IF(MONTHSPERROW = 1, CELLWIDTH, (CELLWIDTH * 19) \ 20)
|
||||
|
||||
DIM CELLHEIGHT = MONTHGRIDHEIGHT \ CALENDARROWCOUNT
|
||||
DIM CELLCONTENTHEIGHT = (CELLHEIGHT * 19) \ 20
|
||||
|
||||
' CREATES A MONTH CELL FOR THE SPECIFIED MONTH (1-12).
|
||||
DIM GETMONTHFROM =
|
||||
FUNCTION(M AS INTEGER) BUILDMONTH(
|
||||
DT:=NEW DATE(DT.YEAR, M, 1),
|
||||
WIDTH:=CELLCONTENTWIDTH,
|
||||
HEIGHT:=CELLCONTENTHEIGHT,
|
||||
VERTSTRETCH:=VERTSTRETCH,
|
||||
HORIZSTRETCH:=HORIZSTRETCH).SELECT(FUNCTION(X) X.PADCENTER(CELLWIDTH))
|
||||
|
||||
' THE MONTHS IN THIS ROW OF THE CALENDAR.
|
||||
DIM MONTHSTHISROW AS IENUMERABLE(OF IENUMERABLE(OF STRING)) =
|
||||
ENUMERABLE.SELECT(ENUMERABLE.RANGE(MONTH + 1, ROWHIGHESTMONTH - MONTH), GETMONTHFROM)
|
||||
|
||||
DIM CALENDARROW AS IENUMERABLE(OF STRING) =
|
||||
INTERLEAVED(
|
||||
MONTHSTHISROW,
|
||||
USEINNERSEPARATOR:=FALSE,
|
||||
USEOUTERSEPARATOR:=TRUE,
|
||||
OUTERSEPARATOR:=ENVIRONMENT.NEWLINE)
|
||||
|
||||
DIM EN = CALENDARROW.GETENUMERATOR()
|
||||
DIM HASNEXT = EN.MOVENEXT()
|
||||
DO WHILE HASNEXT
|
||||
|
||||
DIM CURRENT AS STRING = EN.CURRENT
|
||||
|
||||
' TO MAINTAIN THE (NOT STRICTLY NEEDED) CONTRACT OF YIELDING COMPLETE ROWS, KEEP THE NEWLINE AFTER
|
||||
' THE CALENDAR ROW WITH THE LAST TERMINAL ROW OF THE ROW.
|
||||
HASNEXT = EN.MOVENEXT()
|
||||
YIELD IF(HASNEXT, CURRENT, CURRENT & ENVIRONMENT.NEWLINE)
|
||||
LOOP
|
||||
|
||||
MONTH += MONTHSPERROW
|
||||
LOOP
|
||||
END FUNCTION
|
||||
|
||||
''' <SUMMARY>
|
||||
''' INTERLEAVES THE ELEMENTS OF THE SPECIFIED SUB-SOURCES BY MAKING SUCCESSIVE PASSES THROUGH THE SOURCE
|
||||
''' ENUMERABLE, YIELDING A SINGLE ELEMENT FROM EACH SUB-SOURCE IN SEQUENCE IN EACH PASS, OPTIONALLY INSERTING A
|
||||
''' SEPARATOR BETWEEN ELEMENTS OF ADJACENT SUB-SOURCES AND OPTIONALLY A DIFFERENT SEPARATOR AT THE END OF EACH
|
||||
''' PASS THROUGH ALL THE SOURCES. (I.E., BETWEEN ELEMENTS OF THE LAST AND FIRST SOURCE)
|
||||
''' </SUMMARY>
|
||||
''' <TYPEPARAM NAME="T">THE TYPE OF THE ELEMENTS OF THE SUB-SOURCES.</TYPEPARAM>
|
||||
''' <PARAM NAME="SOURCES">A SEQUENCE OF THE SEQUENCES WHOSE ELEMENTS ARE TO BE INTERLEAVED.</PARAM>
|
||||
''' <PARAM NAME="USEINNERSEPARATOR">WHETHER TO INSERT <PARAMREF NAME="USEINNERSEPARATOR"/> BETWEEN THE ELEMENTS OFADJACENT SUB-SOURCES.</PARAM>
|
||||
''' <PARAM NAME="INNERSEPARATOR">THE SEPARATOR BETWEEN ELEMENTS OF ADJACENT SUB-SOURCES.</PARAM>
|
||||
''' <PARAM NAME="USEOUTERSEPARATOR">WHETHER TO INSERT <PARAMREF NAME="OUTERSEPARATOR"/> BETWEEN THE ELEMENTS OF THE LAST AND FIRST SUB-SOURCES.</PARAM>
|
||||
''' <PARAM NAME="OUTERSEPARATOR">THE SEPARATOR BETWEEN ELEMENTS OF THE LAST AND FIRST SUB-SOURCE.</PARAM>
|
||||
''' <PARAM NAME="WHILEANY">IF <SEE LANGWORD="TRUE"/>, THE ENUMERATION CONTINUES UNTIL EVERY GIVEN SUBSOURCE IS EMPTY;
|
||||
''' IF <SEE LANGWORD="FALSE"/>, THE ENUMERATION STOPS AS SOON AS ANY ENUMERABLE NO LONGER HAS AN ELEMENT TO SUPPLY FOR THE NEXT PASS.</PARAM>
|
||||
ITERATOR FUNCTION INTERLEAVED(OF T)(
|
||||
SOURCES AS IENUMERABLE(OF IENUMERABLE(OF T)),
|
||||
OPTIONAL USEINNERSEPARATOR AS BOOLEAN = FALSE,
|
||||
OPTIONAL INNERSEPARATOR AS T = NOTHING,
|
||||
OPTIONAL USEOUTERSEPARATOR AS BOOLEAN = FALSE,
|
||||
OPTIONAL OUTERSEPARATOR AS T = NOTHING,
|
||||
OPTIONAL WHILEANY AS BOOLEAN = TRUE) AS IENUMERABLE(OF T)
|
||||
DIM SOURCEENUMERATORS AS IENUMERATOR(OF T)() = NOTHING
|
||||
|
||||
TRY
|
||||
SOURCEENUMERATORS = SOURCES.SELECT(FUNCTION(X) X.GETENUMERATOR()).TOARRAY()
|
||||
DIM NUMSOURCES = SOURCEENUMERATORS.LENGTH
|
||||
DIM ENUMERATORSTATES(NUMSOURCES - 1) AS BOOLEAN
|
||||
|
||||
DIM ANYPREVITERS AS BOOLEAN = FALSE
|
||||
DO
|
||||
' INDICES OF FIRST AND LAST SUB-SOURCES THAT HAVE ELEMENTS.
|
||||
DIM FIRSTACTIVE = -1, LASTACTIVE = -1
|
||||
|
||||
' DETERMINE WHETHER EACH SUB-SOURCE THAT STILL HAVE ELEMENTS.
|
||||
FOR I = 0 TO NUMSOURCES - 1
|
||||
ENUMERATORSTATES(I) = SOURCEENUMERATORS(I).MOVENEXT()
|
||||
IF ENUMERATORSTATES(I) THEN
|
||||
IF FIRSTACTIVE = -1 THEN FIRSTACTIVE = I
|
||||
LASTACTIVE = I
|
||||
END IF
|
||||
NEXT
|
||||
|
||||
' DETERMINE WHETHER TO YIELD ANYTHING IN THIS ITERATION BASED ON WHETHER WHILEANY IS TRUE.
|
||||
' NOT YIELDING ANYTHING THIS ITERATION IMPLIES THAT THE ENUMERATION HAS ENDED.
|
||||
DIM THISITERHASRESULTS AS BOOLEAN = IF(WHILEANY, FIRSTACTIVE <> -1, FIRSTACTIVE = 0 ANDALSO LASTACTIVE = NUMSOURCES - 1)
|
||||
IF NOT THISITERHASRESULTS THEN EXIT DO
|
||||
|
||||
' DON'T INSERT A SEPARATOR ON THE FIRST PASS.
|
||||
IF ANYPREVITERS THEN
|
||||
IF USEOUTERSEPARATOR THEN YIELD OUTERSEPARATOR
|
||||
ELSE
|
||||
ANYPREVITERS = TRUE
|
||||
END IF
|
||||
|
||||
' GO THROUGH AND YIELD FROM THE SUB-SOURCES THAT STILL HAVE ELEMENTS.
|
||||
FOR I = 0 TO NUMSOURCES - 1
|
||||
IF ENUMERATORSTATES(I) THEN
|
||||
' DON'T INSERT A SEPARATOR BEFORE THE FIRST ELEMENT.
|
||||
IF I > FIRSTACTIVE ANDALSO USEINNERSEPARATOR THEN YIELD INNERSEPARATOR
|
||||
YIELD SOURCEENUMERATORS(I).CURRENT
|
||||
END IF
|
||||
NEXT
|
||||
LOOP
|
||||
|
||||
FINALLY
|
||||
IF SOURCEENUMERATORS ISNOT NOTHING THEN
|
||||
FOR EACH EN IN SOURCEENUMERATORS
|
||||
EN.DISPOSE()
|
||||
NEXT
|
||||
END IF
|
||||
END TRY
|
||||
END FUNCTION
|
||||
|
||||
''' <SUMMARY>
|
||||
''' RETURNS THE ROWS REPRESENTING ONE MONTH CELL WITHOUT TRAILING NEWLINES. APPROPRIATE LEADING AND TRAILING
|
||||
''' WHITESPACE IS ADDED SO THAT EVERY ROW HAS THE LENGTH OF WIDTH.
|
||||
''' </SUMMARY>
|
||||
''' <PARAM NAME="DT">A DATE WITHIN THE MONTH TO REPRESENT.</PARAM>
|
||||
''' <PARAM NAME="WIDTH">THE WIDTH OF THE CELL.</PARAM>
|
||||
''' <PARAM NAME="HEIGHT">THE HEIGHT.</PARAM>
|
||||
''' <PARAM NAME="VERTSTRETCH">IF <SEE LANGWORD="TRUE" />, BLANK ROWS ARE INSERTED TO FIT THE AVAILABLE HEIGHT.
|
||||
''' OTHERWISE, THE CELL HAS A CONSTANT HEIGHT OF </PARAM>
|
||||
''' <PARAM NAME="HORIZSTRETCH">IF <SEE LANGWORD="TRUE" />, THE SPACING BETWEEN INDIVIDUAL DAYS IS INCREASED TO
|
||||
''' FIT THE AVAILABLE WIDTH. OTHERWISE, THE CELL HAS A CONSTANT WIDTH OF 20 CHARACTERS AND IS PADDED TO BE IN
|
||||
''' THE CENTER OF THE EXPECTED WIDTH.</PARAM>
|
||||
ITERATOR FUNCTION BUILDMONTH(DT AS DATE, WIDTH AS INTEGER, HEIGHT AS INTEGER, VERTSTRETCH AS BOOLEAN, HORIZSTRETCH AS BOOLEAN) AS IENUMERABLE(OF STRING)
|
||||
CONST DAY_WDT = 2 ' WIDTH OF A DAY.
|
||||
CONST ALLDAYS_WDT = DAY_WDT * 7 ' WIDTH OF AL LDAYS COMBINED.
|
||||
|
||||
' NORMALIZE THE DATE TO JANUARY 1.
|
||||
DT = NEW DATE(DT.YEAR, DT.MONTH, 1)
|
||||
|
||||
' HORIZONTAL WHITESPACE BETWEEN DAYS OF THE WEEK. CONSTANT OF 6 REPRESENTS 6 SEPARATORS PER LINE.
|
||||
DIM DAYSEP AS NEW STRING(" "C, MATH.MIN((WIDTH - ALLDAYS_WDT) \ 6, IF(HORIZSTRETCH, INTEGER.MAXVALUE, 1)))
|
||||
' NUMBER OF BLANK LINES BETWEEN ROWS.
|
||||
DIM VERTBLANKCOUNT = IF(NOT VERTSTRETCH, 0, (HEIGHT - 8) \ 7)
|
||||
|
||||
' WIDTH OF EACH DAY * 7 DAYS IN ONE ROW + DAY SEPARATOR LENGTH * 6 SEPARATORS PER LINE.
|
||||
DIM BLOCKWIDTH = ALLDAYS_WDT + DAYSEP.LENGTH * 6
|
||||
|
||||
' THE WHITESPACE AT THE BEGINNING OF EACH LINE.
|
||||
DIM LEFTPAD AS NEW STRING(" "C, (WIDTH - BLOCKWIDTH) \ 2)
|
||||
' THE WHITESPACE FOR BLANK LINES.
|
||||
DIM FULLPAD AS NEW STRING(" "C, WIDTH)
|
||||
|
||||
' LINES ARE "STAGED" IN THE STRINGBUILDER.
|
||||
DIM SB AS NEW STRINGBUILDER(LEFTPAD)
|
||||
DIM NUMLINES = 0
|
||||
|
||||
' GET THE CURRENT LINE SO FAR FORM THE STRINGBUILDER AND BEGIN A NEW LINE.
|
||||
' RETURNS THE CURRENT LINE AND TRAILING BLANK LINES USED FOR VERTICAL PADDING (IF ANY).
|
||||
' RETURNS EMPTY ENUMERABLE IF THE HEIGHT REQUIREMENT HAS BEEN REACHED.
|
||||
DIM ENDLINE =
|
||||
FUNCTION() AS IENUMERABLE(OF STRING)
|
||||
DIM FINISHEDLINE AS STRING = SB.TOSTRING().PADRIGHT(WIDTH)
|
||||
SB.CLEAR()
|
||||
SB.APPEND(LEFTPAD)
|
||||
|
||||
' USE AN INNER ITERATOR TO PREVENT LAZY EXECUTION OF SIDE EFFECTS OF OUTER FUNCTION.
|
||||
RETURN IF(NUMLINES >= HEIGHT,
|
||||
ENUMERABLE.EMPTY(OF STRING)(),
|
||||
ITERATOR FUNCTION() AS IENUMERABLE(OF STRING)
|
||||
YIELD FINISHEDLINE
|
||||
NUMLINES += 1
|
||||
|
||||
FOR I = 1 TO VERTBLANKCOUNT
|
||||
IF NUMLINES >= HEIGHT THEN RETURN
|
||||
YIELD FULLPAD
|
||||
NUMLINES += 1
|
||||
NEXT
|
||||
END FUNCTION())
|
||||
END FUNCTION
|
||||
|
||||
' YIELD THE MONTH NAME.
|
||||
SB.APPEND(PADCENTER(DT.TOSTRING("MMMM", CULTUREINFO.INVARIANTCULTURE), BLOCKWIDTH).TOUPPER())
|
||||
FOR EACH L IN ENDLINE()
|
||||
YIELD L
|
||||
NEXT
|
||||
|
||||
' YIELD THE HEADER OF WEEKDAY NAMES.
|
||||
DIM WEEKNMABBREVS = [ENUM].GETNAMES(GETTYPE(DAYOFWEEK)).SELECT(FUNCTION(X) X.SUBSTRING(0, 2).TOUPPER())
|
||||
SB.APPEND(STRING.JOIN(DAYSEP, WEEKNMABBREVS))
|
||||
FOR EACH L IN ENDLINE()
|
||||
YIELD L
|
||||
NEXT
|
||||
|
||||
' DAY OF WEEK OF FIRST DAY OF MONTH.
|
||||
DIM STARTWKDY = CINT(DT.DAYOFWEEK)
|
||||
|
||||
' INITIALIZE WITH EMPTY SPACE FOR THE FIRST LINE.
|
||||
DIM FIRSTPAD AS NEW STRING(" "C, (DAY_WDT + DAYSEP.LENGTH) * STARTWKDY)
|
||||
SB.APPEND(FIRSTPAD)
|
||||
|
||||
DIM D = DT
|
||||
DO WHILE D.MONTH = DT.MONTH
|
||||
SB.APPENDFORMAT(CULTUREINFO.INVARIANTCULTURE, $"{{0,{DAY_WDT}}}", D.DAY)
|
||||
|
||||
' EACH ROW ENDS ON SATURDAY.
|
||||
IF D.DAYOFWEEK = DAYOFWEEK.SATURDAY THEN
|
||||
FOR EACH L IN ENDLINE()
|
||||
YIELD L
|
||||
NEXT
|
||||
ELSE
|
||||
SB.APPEND(DAYSEP)
|
||||
END IF
|
||||
|
||||
D = D.ADDDAYS(1)
|
||||
LOOP
|
||||
|
||||
' KEEP ADDING EMPTY LINES UNTIL THE HEIGHT QUOTA IS MET.
|
||||
DIM NEXTLINES AS IENUMERABLE(OF STRING)
|
||||
DO
|
||||
NEXTLINES = ENDLINE()
|
||||
FOR EACH L IN NEXTLINES
|
||||
YIELD L
|
||||
NEXT
|
||||
LOOP WHILE NEXTLINES.ANY()
|
||||
END FUNCTION
|
||||
|
||||
''' <SUMMARY>
|
||||
''' RETURNS A NEW STRING THAT CENTER-ALIGNS THE CHARACTERS IN THIS STRING BY PADDING TO THE LEFT AND RIGHT WITH
|
||||
''' THE SPECIFIED CHARACTER TO A SPECIFIED TOTAL LENGTH.
|
||||
''' </SUMMARY>
|
||||
''' <PARAM NAME="S">THE STRING TO CENTER-ALIGN.</PARAM>
|
||||
''' <PARAM NAME="TOTALWIDTH">THE NUMBER OF CHARACTERS IN THE RESULTING STRING.</PARAM>
|
||||
''' <PARAM NAME="PADDINGCHAR">THE PADDING CHARACTER.</PARAM>
|
||||
<EXTENSION()>
|
||||
PRIVATE FUNCTION PADCENTER(S AS STRING, TOTALWIDTH AS INTEGER, OPTIONAL PADDINGCHAR AS CHAR = " "C) AS STRING
|
||||
RETURN S.PADLEFT(((TOTALWIDTH - S.LENGTH) \ 2) + S.LENGTH, PADDINGCHAR).PADRIGHT(TOTALWIDTH, PADDINGCHAR)
|
||||
END FUNCTION
|
||||
END MODULE
|
||||
Loading…
Add table
Add a link
Reference in a new issue