Kbase 17952: How To Programmatically Beautify Progress Procedures.
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  16/10/2008 |
|
Status: Unverified
GOAL:
How to programmatically beautify Progress procedures.
FIX:
/* THIS SOLUTION IS FOR INFORMATIONAL PURPOSES ONLY. Please test
extensively prior to using this on your own source code.
Programmers are hereby notified that use is at their own risk. */
/* The code below is for BEAUTY.P, a procedure that was included
in the Version 6 Librarian. This solution provides this code
for users who are on versions later than Version 6. */
/* Another note: this code was written prior to PROGRESS being
a true Windows client, therefore does not take Windows into account. */
DISPLAY STRING(TODAY,"99/99/99") "Beautify Program" AT 32 "Ver 2.5" TO 77
WITH FRAME stdhead WIDTH 80.
DEFINE STREAM prog.
DEFINE NEW GLOBAL SHARED VARIABLE m-file AS c FORMAT "x(40)" LABEL " Input File Spec" NO-UNDO.
DEFINE NEW GLOBAL SHARED VARIABLE m-Extend AS LOG LABEL "Unabbreviate keywords" INITIAL NO.
DEFINE VARIABLE m-CFil AS c FORMAT "x(40)" NO-UNDO.
DEFINE VARIABLE m-filara AS c FORMAT "x(40)" EXTENT 1000 NO-UNDO.
DEFINE VARIABLE m-First AS l INITIAL YES.
DEFINE VARIABLE m-tmpfile AS c FORMAT "x(40)".
DEFINE VARIABLE m-filnum AS i NO-UNDO.
DEFINE VARIABLE m-linnum AS i LABEL "Line Number" NO-UNDO.
DEFINE VARIABLE m-Inp AS c FORMAT "x(40)" EXTENT 2.
DEFINE VARIABLE m-iline AS c FORMAT "x(250)" NO-UNDO.
DEFINE VARIABLE m-indent AS i NO-UNDO. /* # of spaces to
indent next line */
DEFINE VARIABLE m-cont AS l NO-UNDO. /* this command was continued */
/* m-cont = no means we just found the end of a command. */
/* m-cont = yes means we are processing a command
(not just comments, .i ..) */
/* m-cont = ? we finished a command but have not gotten
to another yet */
DEFINE VARIABLE m-lpos AS i NO-UNDO. /* char position in current line */
DEFINE VARIABLE m-OLen AS i NO-UNDO. /* position of next potential word */
DEFINE VARIABLE m-LineLen AS i NO-UNDO. /* Length of current line */
DEFINE VARIABLE m-scr1 AS i NO-UNDO.
DEFINE VARIABLE m-scr2 AS i NO-UNDO.
DEFINE VARIABLE m-comment AS i NO-UNDO. /* nested comment level */
DEFINE VARIABLE m-quote AS l NO-UNDO. /* are we in a quoted string */
DEFINE VARIABLE m-curword AS c NO-UNDO. /* word we are working on */
DEFINE VARIABLE m-curwordpos AS i NO-UNDO. /* position of current word */
DEFINE VARIABLE m-CurlyNest AS i NO-UNDO. /* nested curly level */
DEFINE VARIABLE m-CurlyState AS l NO-UNDO. /* cont state @ start of curl */
DEFINE VARIABLE m-ITE AS INTEGER NO-UNDO. /* If then else Funct next level */
DEFINE VARIABLE m-CapIt AS LOGICAL NO-UNDO. /* should any more words */
DEFINE VARIABLE t-Inp AS CHARACTER FORMAT "x(40)".
DEFINE VARIABLE file-input AS CHARA.CTER.
ASSIGN
m-filara = ?
m-tmpfile = "tmp" + STRING(TIME,"99999")
file-input = SEARCH("beauty.fn").
FORMAT WITH FRAME out-prog NO-ATTR-SPACE NO-BOX
NO-LABELS DOWN WIDTH 250.
IF file-input = ? THEN
UPDATE
m-file VALIDATE(m-file > "",
"Please enter input file spec") SKIP
m-Extend
HELP "Do you want abbreviated keywords to be typed out"
WITH SIDE-LABELS 1 COLUMNS CENTERED FRAME info.
ELSE
DO:
INPUT FROM VALUE(file-input) NO-ECHO.
SET m-file m-Extend WITH FRAME info.
INPUT CLOSE.
END.
IF OPSYS = "UNIX" THEN
DO:
INPUT THROUGH ls VALUE(m-file) NO-ECHO.
REPEAT m-filnum = 1 TO 1000:
SET m-filara[m-filnum] WITH NO-BOX NO-LABELS.
END.
INPUT CLOSE.
END.
ELSE
IF OPSYS = "MSDOS" THEN
DO:
DOS SILENT dir VALUE(m-file) > VALUE(m-tmpfile + ".t").
INPUT FROM VALUE(m-tmpfile + ".t") NO-ECHO.
SET ^.
SET ^.
SET ^ ^ t-Inp.
SET ^.
REPEAT m-filnum = 1 TO 1000:
ASSIGN m-Inp = "".
SET m-Inp.
IF NOT CAN-DO("
,file(s)",m-Inp[2]) THEN
ASSIGN m-filara[m-filnum] = t-Inp +
"~\" + m-Inp[1] + "." + m-Inp[2].
END.
INPUT CLOSE.
DOS SILENT del VALUE(m-tmpfile + ".t").
END.
ELSE
IF OPSYS = "VMS" THEN
DO:
VMS SILENT VALUE("dir/size/vers=1/output=" +
m-tmpfile + ".t " + m-file).
INPUT FROM VALUE(m-tmpfile + ".t") NO-ECHO.
ASSIGN m-filnum = 0.
REPEAT:
ASSIGN m-Inp = "".
SET m-Inp WITH NO-BOX NO-LABELS.
IF m-Inp[1] = "DIRECTORY" THEN
ASSIGN t-Inp = m-Inp[2].
IF INDEX(m-Inp[1],";") > 0 THEN
ASSIGN
m-filnum = m-filnum + 1
m-filara[m-filnum] = t-Inp +
SUBSTRING(m-Inp[1],1,INDEX(m-Inp[1],";") - 1).
END.
INPUT CLOSE.
END.
ELSE
IF OPSYS = "BTOS" THEN
DO:
BTOS SILENT "[Sys]Files.run"
Files VALUE(m-file) "NO"
VALUE(m-tmpfile + ".t") "NO" 1.
INPUT FROM VALUE(m-tmpfile + ".t") NO-ECHO.
REPEAT m-filnum = 1 TO 1000:
ASSIGN m-filara[m-filnum] = "".
SET m-filara[m-filnum] WITH NO-BOX NO-LABELS.
END.
INPUT CLOSE.
END.
get-file:
REPEAT m-filnum = 1 TO 1000:
ASSIGN m-CFil = SEARCH(m-filara[m-filnum]).
IF m-CFil = ? THEN
NEXT.
DISPLAY m-CFil @ m-file WITH FRAME info.
IF OPSYS = "UNIX" THEN
UNIX SILENT VALUE(SEARCH("quoter") + " " +
m-CFil + ">" + m-tmpfile + ".q").
ELSE
IF OPSYS = "MSDOS" THEN
DOS SILENT quoter.exe VALUE(m-CFil) >
VALUE(m-tmpfile + ".q").
ELSE
IF OPSYS = "VMS" THEN
DO:
/* the following lines are used if progress
commands not available in shell */
OUTPUT TO VALUE(m-tmpfile + ".t").
DISPLAY
"$ set command dlc:progress" SKIP
"$ progress/tools=quoter/output=" +
m-tmpfile + ".q " + m-CFil
&n.bsp; FORMAT "x(80)" WITH FRAME VMS-cmd
NO-ATTR-SPACE NO-LABELS NO-BOX.
OUTPUT CLOSE.
VMS SILENT VALUE("@" + m-tmpfile + ".t").
/* Use this line instead if progress commands
are available in a shell
VMS SILENT VALUE("PROGRESS/TOOLS=quoter/OUTPUT=" +
m-tmpfile + ".q") m-CFil.
*/
END.
ELSE
IF OPSYS="BTOS" THEN
BTOS VALUE(SEARCH("quoter.run") + " quoter "
+ m-CFil + " >" + m-tmpfile + ".q").
INPUT FROM VALUE(m-tmpfile + ".q") NO-ECHO.
OUTPUT STREAM prog TO VALUE(m-tmpfile + ".n").
ASSIGN
m-CurlyNest = 0
m-indent = 0
m-comment = 0
m-linnum = 1
m-cont = ?
m-ITE = 0
m-quote = FALSE
m-First = YES.
REPEAT ON ERROR UNDO, NEXT get-file:
SET m-iline WITH NO-ATTR-SPACE FRAME
iline WIDTH 250 NO-BOX NO-LABELS.
IF m-First = YES AND SUBSTRING(m-iline,1,2) <> "/*" THEN
DISPLAY STREAM prog
"/" + FILL("*",75) + "~\" FORMAT "x(77)"
FILL("*",77) FORMAT "x(77)"
"** Program: " + m-filara[m-filnum] FORMAT "x(40)" SKIP
"** By:" SKIP
"** Descript:" SKIP
"**" SKIP
FILL("*",77) FORMAT "x(77)"
"~\" + FILL("*",75) + "/" FORMAT "x(77)" SKIP(1)
WITH FRAME prg-hd NO-BOX NO-LABELS NO-ATTR-SPACE.
ASSIGN m-First = NO.
/* loop for each command in an input line */
line-loop:
DO WHILE TRUE ON ERROR UNDO, NEXT get-file:
/*
* if we are not in quoted material
* Strip off leading spaces then insert proper indent
*/
IF NOT m-quote THEN
DO:
DO WHILE m-iline BEGINS CHR(9) OR m-iline BEGINS " ":
SUBSTRING(m-iline,1,1) = "".
END.
ASSIGN
m-lpos = 1 + m-indent + IF m-cont
OR m-CurlyNest > 0 THEN 2 ELSE 0
SUBSTRING(m-iline,1,0) = FILL(" ",m-lpos - 1).
END.
ELSE
ASSIGN m-lpos = 1.
ASSIGN
m-LineLen = LENGTH(m-iline)
m-CapIt = IF m-cont = ? THEN YES ELSE m-CapIt.
/* loop through the characters in a command */
cmd-loop:
DO WHILE m-lpos <= m-LineLen ON ERROR UNDO, NEXT get-file:
/* Skip over comment sections */
IF (m-comment > 0 OR SU.BSTRING(m-iline,m-lpos,2) = "/*")
AND NOT m-quote THEN
DO:
ASSIGN m-scr1 = INDEX(SUBSTRING(m-iline,m-lpos),"/*")
m-scr2 = INDEX(SUBSTRING(m-iline,m-lpos),"*/").
/* if no markers found goto next line
- dont change status */
IF m-scr1 = 0 AND m-scr2 = 0 THEN
ASSIGN m-lpos = m-LineLen + 1.
/* found a beginning marker before an ending marker */
ELSE
IF m-scr1 > 0 AND (m-scr1 < m-scr2 OR m-scr2 = 0) THEN
ASSIGN m-comment = m-comment + 1
m-lpos = m-scr1 + m-lpos + 1.
/* must have found a ending marker before an
beginning marker */
ELSE
ASSIGN m-comment = IF m-comment > 0 THEN
m-comment - 1 ELSE 0
m-lpos = m-scr2 + m-lpos + 1.
NEXT cmd-loop.
END. /* end of comment check */
/* Skip over quoted material */
IF m-quote OR SUBSTRING(m-iline,m-lpos,1) = """" THEN
DO:
ASSIGN m-scr1 = INDEX(SUBSTRING(m-iline,m-lpos),"""")
M-lpos = m-lpos + m-scr1.
/* if no markers found goto next line -
dont change status */
IF m-scr1 = 0 THEN
ASSIGN m-lpos = m-LineLen + 1.
ELSE
IF SUBSTRING(m-iline,m-lpos - 1,1) NE "~~" THEN
ASSIGN m-quote = NOT m-quote.
NEXT cmd-loop.
END. /* end of quote check */
/* Skip over any delimiters before the next word */
IF INDEX("~{~}()[],=+ " +
CHR(9),SUBSTRING(m-iline,m-lpos,1)) > 0 THEN
nxt_word:
DO:
DO WHILE
INDEX("~{~}()[],=+ " +
CHR(9),SUBSTRING(m-iline,m-lpos,1)) > 0
 .; AND m-lpos <= m-LineLen:
/* if we find anything other than
a space after a command then
* it needs to go on its own line
*/
IF SUBSTRING(m-iline,m-lpos,1) NE " "
AND NOT m-cont THEN
LEAVE nxt_word.
IF SUBSTRING(m-iline,m-lpos,1) = "~{" THEN
ASSIGN
m-CurlyNest = m-CurlyNest + 1
m-CurlyState =
(IF m-CurlyNest = 1 THEN m-cont ELSE m-CurlyState).
ELSE
IF SUBSTRING(m-iline,m-lpos,1) = "~}" THEN
ASSIGN
m-CurlyNest = m-CurlyNest - 1
m-cont =
(IF m-CurlyNest > 0 THEN m-cont ELSE m-CurlyState).
ASSIGN m-lpos = m-lpos + 1.
END.
NEXT cmd-loop.
END.
/* If we just found the end of a
command on the last iteration */
/* of this loop then this is the
second command on this line and */
/* we need to write the first command
out to a line of it's own */
IF NOT m-cont THEN
DO:
ASSIGN m-lpos = m-lpos - 1.
LEAVE cmd-loop.
END.
/* find the next word */
ASSIGN m-OLen = 1.
DO WHILE INDEX("~{~}()[],=+ " + CHR(9),
SUBSTRING(m-iline,m-lpos + m-OLen,1)) = 0
AND m-lpos + m-OLen <= m-LineLen:
ASSIGN m-OLen = m-OLen + 1.
END.
/* Get the next word */
ASSIGN m-curword =
SUBSTRING(m-iline,m-lpos,m-OLen).
/* It is possible to concatinate a comment
 .; to the end of a command or "word" in
PROGRESS. Although this is ugly
programming we need to code for it.
I decrement m-lpos after I strip
off the comment so that it will point
to the beginning of the comment
after the increment which follows it. */
IF INDEX(m-curword,"/*") > 0 THEN
ASSIGN
m-comment = 1
m-curword = SUBSTRING(m-curword,1,
INDEX(m-curword,"/*") - 1).
/* does word end in a . or a :? */
IF INDEX(".:",
SUBSTRING(m-curword,LENGTH(m-curword),1))
> 0 AND
SUBSTRING(m-iline,m-lpos +
LENGTH(m-curword),1) <= " " THEN
ASSIGN SUBSTRING(m-curword,
LENGTH(m-curword),1) = ""
m-cont = NO.
/* did we find an if then else function */
IF m-curword = "IF" AND m-cont = YES THEN
ASSIGN m-ITE = m-ITE + 1.
ELSE
IF m-ITE > 0 AND m-curword = "ELSE" THEN
ASSIGN m-ITE = m-ITE - 1.
/* is this a THEN or an ELSE -
if so then start a new command */
ELSE
IF CAN-DO("THEN,ELSE",m-curword) AND m-ITE = 0 THEN
ASSIGN m-cont = NO.
/* O.K., we have our word now.
Does it define a new block? */
ELSE
IF CAN-DO("do,for,repeat,editing",m-curword)
AND m-cont NE YES THEN
DO:
IF m-lpos > 1 AND
SUBSTRING(m-iline,1,m-lpos - 1) GT " " THEN
DO:
ASSIGN
m-lpos = m-lpos - 1.
LEAVE cmd-loop.
END.
/* indent following commands. */
ASSIGN m-indent = m-indent + 2.
END.
/* is it the end of a block */
ELSE
. IF m-curword = "end" AND m-iline BEGINS " " THEN
ASSIGN SUBSTRING(m-iline,1,2) = ""
m-LineLen = m-LineLen - 2
m-lpos = m-lpos - 2
m-indent = m-indent - 2.
/* if it is a keyword then cap it */
ASSIGN t-Inp = KEYWORD(m-curword).
IF t-Inp NE ? AND m-CapIt THEN
DO:
IF m-Extend THEN
ASSIGN
m-OLen = m-OLen - LENGTH(m-curword) + LENGTH(t-Inp)
SUBSTRING(m-iline,m-lpos,LENGTH(m-curword)) = t-Inp
m-LineLen = LENGTH(m-iline).
ELSE
ASSIGN SUBSTRING(m-iline,m-lpos) = CAPS(m-curword).
IF CAN-DO("THRU,THROUGH,DOS,UNIX,VMS,BTOS,CTOS",
t-Inp) THEN
ASSIGN m-CapIt = NO.
IF m-cont = ? AND LENGTH(t-inp) > 1 THEN
ASSIGN m-cont = YES.
END.
/* position pointer after the current word */
ASSIGN m-lpos = m-lpos + m-OLen.
END. /* end of word parse cmd-loop */
/* Write out our command to program file */
DISPLAY STREAM prog
SUBSTRING(m-iline,1,m-lpos) FORMAT "x(250)"
WITH FRAME out-prog.
DOWN STREAM prog WITH FRAME out-prog.
/* Write out new line to screen */
DISPLAY m-linnum WITH FRAME info.
/* if we are not at the end of current
command then we're continued */
ASSIGN m-linnum = m-linnum + 1
m-cont = IF m-cont = NO THEN ? ELSE m-cont
m-iline = SUBSTRING(m-iline,m-lpos + 1).
IF m-iline = "" THEN
LEAVE line-loop.
END. /* end of individule line parser line-loop */
END. /* end of line reading loop get-file */
OUTPUT STREAM prog CLOSE.
IF OPSYS = "UNIX" THEN
UNIX SILENT cp VALUE(m-tmpfile + ".n " + m-CFil)
"&& .