source: branches/create_TK_docs.CMD@ 174

Last change on this file since 174 was 173, checked in by erdmann, 15 months ago

Merged changes from Gregg's branch

File size: 21.3 KB
Line 
1/* Create documentation for functions */
2 call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
3 call SysLoadFuncs
4
5/* Set this to '1' to get debug messages */
6DEBUG=0
7
8docInfo.=''
9
10theDir=ARG(1)
11
12IF theDir="" THEN theDir=STRIP(DIRECTORY())
13
14/* Where to place the generated IPF source */
15docdir="r:\temp"
16ipf=docdir||'\CWTKDoc.ipf' /* The IPF file */
17
18SAY "Base directory: "theDir
19SAY
20
21/*** Read all the C files and parse them ***/
22SAY "Checking C files..."
23rc=SysFileTree(theDir"\*.c", "files.", "FSO")
24
25IF DEBUG=1 THEN DO
26 SAY "Found the following C files:"
27 DO a= 1 to files.0
28 SAY " "||a||" "||files.a
29 END
30 SAY ""
31END
32
33numLines=0
34index=0 /* This index holds the number of found descriptions */
35DO a = 1 to files.0
36 /* The stem contents holds the lines of the C source file */
37 drop contents
38 contents.=''
39 numLines=0
40 /* Count and read in lines of file */
41 DO WHILE LINES(files.a)
42 numLines=numLines+1
43 contents.numlines=LINEIN(files.a)
44 END
45 contents.0=numLines
46 call STREAM files.a, "C","close"
47
48 /* Now parse each source file */
49 exposeList='files. theLine numLines index docinfo. contents.'
50 call parseFile a
51END
52
53
54IF files.0\=0 THEN DO
55 result._C=files.0
56 result._CLines=numLines
57END
58ELSE DO
59 result._C=0
60 result._CLines=0
61END
62
63
64SAY ""
65SAY result._Clines||" lines in "||result._c||" C files"
66
67IF DEBUG=1 THEN DO
68 /* Show the information we got */
69 DO a= 1 to index
70 SAY ''
71 SAY a||': '
72 SAY 'Function: 'docinfo.a.function
73 SAY 'Line: 'docinfo.a.line
74 SAY'Desc: 'docinfo.a.desc
75 SAY 'File: 'docinfo.a.file
76 END
77END
78
79/*create docs */
80res=200 /* The initial res id */
81leftWidth="30%"
82syntaxres=1 /* Res id for syntax table. To be added to base. E.G. 201 */
83remarksres=2
84returnsres=3
85exampleres=4
86overrideres=5
87usageres=6
88paramsres=10
89
90'@type NUL > 'ipf
91
92/* Write IPF header */
93call writeIpfHeader ipf
94
95/* Sort the function names in the array a. */
96a.=''
97DO b= 1 to index
98 a.b=STRIP(WORD(docinfo.b.function,2))
99END
100a.0=index
101call qqsort 1, index
102
103IF DEBUG=1 THEN DO
104 /* Show the sorted functions */
105 SAY 'Sorted functionarray:'
106 DO b= 1 to index
107 SAY b||': 'a.b
108 END
109END
110
111/* Build a stem with the right order of indexes so in the document the functions are ordered */
112indStem.=''
113DO b=1 to index
114 DO c=1 to index
115 if STRIP(WORD(docinfo.c.function,2))=a.b THEN DO
116 indStem.b=c
117 LEAVE
118 END
119 END
120END
121
122/* Write function reference */
123call writeIpfFunctionRef ipf
124
125/* Footer */
126call writeIpfFooter ipf
127
128call STREAM ipf, "C","close"
129
130/* Compile the document */
131'@ipfc -i 'ipf
132
133exit
134
135/**************** Procedures *********************************/
136
137writeIpfFunctionRef:
138
139 IF DEBUG=1 THEN SAY "DEBUG: Writing function reference..."
140 res=res+100
141 call lineout ipf, ":h1 res="||res||".Function reference"
142 call lineout ipf, ""
143
144 /* Write the function descriptions. The syntax pane is always written. The others only if
145 sufficient information is available. */
146 DO b=1 to index
147 a=indStem.b
148 res=res+100
149 call writeIpfFunction /* Write header for this function desc panel */
150 call writeIpfFuncLinks /* Add links to left pane (Syntax, remarks...) */
151 call writeIpfFuncSyntax /* Write Syntax pane */
152 call writeIpfFuncReturns /* Write return pane (lower right) */
153 call writeIpfFuncRemarks /* Write remarks pane */
154 call writeIpfFuncParams /* Write a pane for every known parameter */
155 call writeIpfFuncOverride /* Write a panel for the override information */
156 call writeIpfFuncUsage /* Write a panel for the Usage information */
157 END
158return
159
160/*********************/
161writeIpfFunction:
162 /* Write the header of the function panel */
163 call lineout ipf, ".*************** "||getFunctionName(docinfo.a.function)||"() *****************"
164 call lineout ipf, ":h2 res="||res
165 call lineout ipf, "width="leftWidth
166 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom) /* Function name */
167 call lineout ipf, ":link reftype=hd res="res+syntaxres /* Syntax will be opened initialy */
168 call lineout ipf, "auto dependent group=2."
169 call lineout ipf, ":p."
170return
171
172/*******************************************/
173/* Write the links in the left panel for */
174/* this function. */
175/*******************************************/
176writeIpfFuncLinks:
177 /* Syntax link is always written */
178 call lineout ipf, ":link reftype=hd res="||res+syntaxres||" dependent.Syntax:elink."
179 call lineout ipf, ".br"
180 if docinfo.a.numparams ><0 THEN DO
181 call lineout ipf, ":link reftype=hd res="||res+paramsres||" dependent.Parameters:elink."
182 call lineout ipf, ".br"
183 END
184 IF docinfo.a.returns >< "" THEN DO
185 call lineout ipf, ":link reftype=hd res="||res+returnsres||" dependent.Returns:elink."
186 call lineout ipf, ".br"
187 END
188 IF docinfo.a.remarks >< "" THEN DO
189 call lineout ipf, ":link reftype=hd res="||res+remarksres||" dependent.Remarks:elink."
190 call lineout ipf, ".br"
191 END
192 IF docinfo.a.override><"" THEN DO
193 call lineout ipf, ":link reftype=hd res="||res+overrideres||" dependent.How to override:elink."
194 call lineout ipf, ".br"
195 END
196 IF docinfo.a.usage><"" THEN DO
197 call lineout ipf, ":link reftype=hd res="||res+usageres||" dependent.Usage:elink."
198 call lineout ipf, ".br"
199 END
200 IF docinfo.index.example >< "" THEN DO
201 call lineout ipf, ":link reftype=hd res="||res+exampleres||" dependent.Example:elink."
202 call lineout ipf, ".br"
203 END
204return
205
206/*********************************/
207/* Write the panel for the return value */
208/*********************************/
209writeIpfFuncReturns:
210 if docinfo.a.returns="" THEN return
211
212 call lineout ipf, ":h2 res="||res+returnsres
213 call lineout ipf, "x=30%"
214 call lineout ipf, "width=70% height=35%"
215 call lineout ipf, "group=3"
216 call lineout ipf, "hide"
217 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" Return value - "||WORD(docinfo.a.returns, 2)
218 call lineout ipf, ":p."
219 call lineout ipf, ":hp2."||WORD(docinfo.a.returns, 2)||":ehp2. ("||WORD(docinfo.a.returns, 1)||") - returns"
220 call lineout ipf, ":p."
221 call lineout ipf, wrapString(SUBWORD(docinfo.a.returns, 3))
222return
223
224/*****************/
225writeIpfFuncOverride:
226 if docinfo.a.override="" THEN return
227
228 call lineout ipf, ":h2 res="||res+overrideres
229 call lineout ipf, "x=30%"
230 call lineout ipf, "width=70%"
231 call lineout ipf, "group=2"
232 call lineout ipf, "hide"
233 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" - How to override"
234 call lineout ipf, ":p."
235 call lineout ipf, wrapString(docinfo.a.override)
236
237return
238
239/*****************/
240writeIpfFuncUsage:
241 if docinfo.a.usage="" THEN return
242
243 call lineout ipf, ":h2 res="||res+usageres
244 call lineout ipf, "x=30%"
245 call lineout ipf, "width=70%"
246 call lineout ipf, "group=2"
247 call lineout ipf, "hide"
248 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" - Usage"
249 call lineout ipf, ":p."
250 call lineout ipf, wrapString(docinfo.a.usage)
251
252return
253
254/*****************/
255writeIpfFuncParams:
256 if docinfo.a.numparams=0 THEN return /* No params given */
257
258 /* Write big parameter panel */
259 call lineout ipf, ":h2 res="||res+paramsres
260 call lineout ipf, "x=30%"
261 call lineout ipf, "width=70%"
262 call lineout ipf, "group=2"
263 call lineout ipf, "hide"
264 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" - Parameters"
265 call lineout ipf, ":p."
266 DO parms = 1 to docinfo.a.numparams
267 pindex='param'||parms
268 call lineout ipf, ":hp2."||WORD(docinfo.a.pindex, 2)||":ehp2. ("||WORD(docinfo.a.pindex, 1)||") - "||WORD(docinfo.a.pindex, 3)
269 call lineout ipf, ":p."
270 call lineout ipf, ":lm margin=5."
271 call lineout ipf, wrapString(SUBWORD(docinfo.a.pindex, 4))
272 call lineout ipf, ":lm margin=1."
273 call lineout ipf, ":p."
274 END
275 call lineout ipf, "" /* Space to make source readable */
276
277 /* Write small panel (lower right) for every parameter */
278 DO parms = 1 to docinfo.a.numparams
279 pindex='param'||parms
280 call lineout ipf, ":h2 res="||res+paramsres+parms
281 call lineout ipf, "x=30%"
282 call lineout ipf, "width=70% height=35%"
283 call lineout ipf, "group=3"
284 call lineout ipf, "hide"
285 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" Parameter - "||WORD(docinfo.a.pindex, 2)
286 call lineout ipf, ":p."
287 call lineout ipf, ":hp2."||WORD(docinfo.a.pindex, 2)||":ehp2. ("||WORD(docinfo.a.pindex, 1)||") - "||WORD(docinfo.a.pindex, 3)
288 call lineout ipf, ":p."
289 call lineout ipf, wrapString(SUBWORD(docinfo.a.pindex, 4))
290 END
291return
292
293/*****************************/
294/* Write the Remarks panel */
295/*****************************/
296writeIpfFuncRemarks:
297 if docinfo.a.remarks="" THEN return
298
299 call lineout ipf, ":h2 res="||res+remarksres
300 call lineout ipf, "x=30%"
301 call lineout ipf, "width=70%"
302 call lineout ipf, "group=2"
303 call lineout ipf, "hide"
304 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" - Remarks"
305 call lineout ipf, ":p."
306 call lineout ipf, wrapString(docinfo.a.remarks)
307
308return
309
310/*****************/
311writeIpfFuncSyntax:
312 /* docinfo.a.function contains the full function header: e.g. 'BOOL theFunc(char theChar)' */
313 call lineout ipf, ""
314 call lineout ipf, ":h2 res="||res+syntaxres
315 call lineout ipf, "x=30%"
316 call lineout ipf, "width=70%"
317 call lineout ipf, "group=2"
318 call lineout ipf, "hide"
319 call lineout ipf, "."||getFunctionName2(docinfo.a.function, docinfo.a.isSom)||" - Syntax"
320 call lineout ipf, ":p."
321 call lineout ipf, wrapString(docinfo.a.desc)
322 call lineout ipf, ":nt."
323 call lineout ipf, "This function can be found in the source file :hp2."||FILESPEC("name", docinfo.a.file) ||":ehp2.."
324 call lineout ipf, ":ent."
325 call lineout ipf, ":xmp."
326 call lineout ipf, ""
327 call lineout ipf, ":parml compact tsize=25 break=none."
328 /* Check if parameters are given. If yes print them and provide a link in the syntax panel */
329 allParams=''
330 IF docinfo.a.numparams >< 0 THEN DO
331 DO parms = 1 to docinfo.a.numparams
332 pindex='param'||parms
333 allParams=allParams||":pt."||WORD(docinfo.a.pindex, 1)||":pd.:link reftype=hd res="||res+paramsres+parms||" dependent."WORD(docinfo.a.pindex, 2 )":elink.;"
334 END
335 END
336 /* Check if return info is given. If yes provide a link on syntax panel */
337 IF docinfo.a.returns >< "" THEN DO
338 allParams=allParams||":pt."||WORD(docinfo.a.returns, 1)||":pd.:link reftype=hd res="||res+returnsres||" dependent."WORD(docinfo.a.returns, 2 )":elink.;"
339 theString=WORD(docinfo.a.returns,2)||" = "||removeTypesFromFunc(SUBWORD(docinfo.a.function,2))||';'
340 END /* docinfo.a.returns */
341 ELSE
342 theString=removeTypesFromFunc(SUBWORD(docinfo.a.function,2))||';'
343 call lineout ipf, allParams
344 call lineout ipf, ":eparml."
345 thePos=1
346 tabPos=1
347 /* Split function in lines */
348 DO WHILE thePos >< 0
349 theString=STRIP(SUBSTR(theString, thePos))
350 thePos=POS(',' , theString)
351 if thePos >< 0 THEN DO
352 if tabPos=1 then DO
353 call lineout ipf, LEFT(theString, thePos)
354 tabPos=POS('(' , theString)
355 END
356 ELSE
357 call lineout ipf, COPIES(' ',tabPos)||LEFT(theString, thePos)
358 thePos=thePos+1
359 END
360 ELSE
361 call lineout ipf, COPIES(' ',tabPos)||theString
362 END
363 call lineout ipf, ":exmp."
364 call lineout ipf, ""
365return
366
367/***************************/
368writeIpfHeader: procedure expose res
369ipf=ARG(1)
370 IF DEBUG=1 THEN
371 SAY "DEBUG: Writing IPF header..."
372 call lineout ipf, ":userdoc."
373 call lineout ipf, ""
374 call lineout ipf, ":docprof."
375 call lineout ipf, ""
376 call lineout ipf, ":title.Function reference"
377 call lineout ipf, ""
378 call lineout ipf, ":h1 res=100.Introduction"
379 call lineout ipf, ":p."
380 call lineout ipf, "Created "DATE()
381 call lineout ipf, ":p."
382 call lineout ipf, "To be written..."
383return
384
385/**************************/
386writeIpfFooter:
387 IF DEBUG=1 THEN
388 SAY "DEBUG: Writing IPF footer..."
389 /* Footer */
390 call lineout ARG(1), ":euserdoc."
391return
392
393
394/*************************************/
395/* This proc removes the types from */
396/* the function definition but keeps */
397/* the var names. */
398/*************************************/
399removeTypesFromFunc: procedure
400 theString=SPACE(ARG(1))
401 /* Make sure there's always a space after '(' and ',' */
402 thePos=POS('(', theString)
403 theString=INSERT(' ', theString, thePos)
404 thePos2=POS(' ' , theString, thePos+3)
405 /* Remove '*' in front of somSelf if any (have to check if this is a hack...) */
406 IF thePos2 >< 0 THEN DO
407 tmpString=STRIP(subStr(theString, thePos2))
408 IF LEFT(tmpString, 1)='*' THEN
409 tmpString=RIGHT(tmpString, LENGTH(tmpString)-1)
410 theString=LEFT(theString, thePos)||STRIP(tmpString)
411 END
412 thePos=POS(',' , theString)
413 DO while thePos >< 0
414 theString=INSERT(' ', theString, thePos)
415 thePos2=POS(' ' , theString, thePos+3)
416/* 12.08.05 be sure a single '*' is removed from any type or var.
417 MAy not work with '**' */
418IF SUBSTR(theString, thePos2+1,1)='*' THEN DO
419 thePos2=thePos2+2
420END
421 theString=LEFT(theString, thePos)||STRIP(subStr(theString, thePos2))
422 thePos=POS(',', theString, thePos+1)
423 END
424return theString
425
426
427/*******************************/
428/* Strip the parameter list from the */
429/* function and return only the name */
430/* */
431/* During file parsing the whole */
432/* function declaration was read in */
433/*******************************/
434getFunctionName: procedure
435 func=ARG(1)
436 thePos=POS('(', func)
437 func=LEFT(func,thePos-1)
438
439return WORD(func,WORDS(func))
440
441/*******************************/
442/* Strip the parameter list from the */
443/* function and return only the name */
444/* */
445/* During file parsing the whole */
446/* function declaration was read in */
447/*******************************/
448getFunctionName2: procedure
449 func=ARG(1)
450 thePos=POS('(', func)
451 func=LEFT(func,thePos-1)
452 func=WORD(func,WORDS(func))
453 IF ARG(2)="YES" THEN
454 return RIGHT(func, LENGTH(func)-1)
455 ELSE
456 return func
457
458/***************************************************************/
459
460/*******************************/
461/* Parse the contents of the source */
462/* file. This means finding comments */
463/* containing function descriptions. */
464/*******************************/
465parseFile: procedure expose (exposelist)
466
467a=ARG(1)
468 curline=0
469 DO while curline <= contents.0
470 curline=curline+1
471 tempLine=STRIP(contents.curline)
472 if LENGTH(templine)<5 then iterate
473
474 if LEFT(tempLine, 4)="/*!*" then do
475 /* Comment with function description found. Now parse it. */
476 call parseComment a
477 END
478 END
479return
480
481/*******************************/
482/* Parse the whole comment block */
483/* with information */
484/*******************************/
485parseComment:
486 index=index+1
487 docinfo.index.file=STRIP(files.a)
488 docinfo.index.remarks=""
489 docinfo.index.returns=""
490 docinfo.index.example=""
491 docinfo.index.numparams=0
492 docinfo.index.override=""
493 docinfo.index.usage=""
494 DO WHILE curline<=contents.0
495 curline=curline+1
496 theLine=STRIP(contents.curline)
497 IF POS("@@",theLine) ><0 THEN call parseEntry /* Found a parameter */
498
499 IF LEFT(STRIP(theLine), 5)="/*!!*" THEN DO
500 /* End of comment. Get function name. */
501 docinfo.index.line=curline+1 /* Line of function */
502 docinfo.index.function=getCompleteFunction()
503 return
504 END
505 END
506return
507
508/********************************/
509/* Read lines until a '{' is found. */
510/* This means reading in a function */
511/* declaration. */
512/* */
513/* */
514/* */
515/********************************/
516
517getCompleteFunction:
518 theLine= ""
519 DO WHILE curline<=contents.0
520 curLine=curLine+1
521 theLine=theLine||STRIP(contents.curline)
522 IF POS("{",theLine) ><0 THEN LEAVE
523 END
524 theLine=STRIP(TRANSLATE(theLine,' ','{'))
525 /* Ok, at this point we have the whole function declaration including the parameters */
526 /* Check if we have a SOM function */
527 IF POS("SOMLINK", theLine) >< 0 THEN DO
528 /* Mark as a SOM function */
529 docinfo.index.isSom="YES"
530 /* Strip SOMLINK and SOM_Scope and the prefix */
531 thePos=POS('_', SUBWORD(theLine, 4))
532 theLine=WORD(theLine, 2)||" "||substr(SUBWORD(theLine,4), thePos)
533
534 END
535return theLine
536
537/*******************************/
538/* Parse entries starting with @@ in */
539/* comment block. */
540/*******************************/
541parseEntry:
542 entry=stripCommentChars(theLine)
543 SELECT
544 WHEN entry="@@DESC" THEN DO
545 /* Description */
546 docinfo.index.desc=readEntryContents()
547 END
548 WHEN entry="@@REMARKS" THEN DO
549 /* Remarks */
550 docinfo.index.remarks=readEntryContents()
551 END
552 WHEN entry="@@RETURNS" THEN DO
553 /* Return value */
554 docinfo.index.returns=readEntryContents()
555 END
556 WHEN entry="@@EXAMPLE" THEN DO
557 /* Example */
558 docinfo.index.example=readEntryContents()
559 END
560 WHEN entry="@@OVERRIDE" THEN DO
561 /* Override of a SOM method */
562 docinfo.index.override=readEntryContents()
563 END
564 WHEN entry="@@USAGE" THEN DO
565 /* Usage of a SOM method */
566 docinfo.index.usage=readEntryContents()
567 END
568 WHEN LEFT(entry, 7)="@@PARAM" THEN DO
569 docinfo.index.numparams=docinfo.index.numparams+1
570 parm='param'||docinfo.index.numparams
571 docinfo.index.parm=readEntryContents()
572 END
573 WHEN entry="@@MODULE" THEN DO
574 /* Module specification */
575 docinfo.index.module=readEntryContents()
576 END
577 OTHERWISE
578 NOP
579 END
580return ""
581
582/************************************/
583/* Read the text associated with a known */
584/* entry. */
585/* Reading takes place until another entry */
586/* is found or the comment ends. */
587/************************************/
588readEntryContents:
589 theEntry=""
590 DO WHILE curline<=contents.0
591 curLine=curLine+1
592 theLine=STRIP(contents.curline)
593 IF POS("@@",theLine) ><0 THEN DO
594 curline=curline-1
595 return theEntry
596 END
597 IF LEFT(STRIP(theLine), 5)="/*!!*" THEN return theEntry
598 /* SAY '!!'||stripCommentChars(theLine)||'!!' */
599
600 if TRANSLATE(stripCommentChars(theLine))=":P." THEN DO
601 theEntry=theEntry||stripCommentChars(theLine)
602 END
603 ELSE DO
604 IF LENGTH(theEntry)>3 THEN DO
605 IF TRANSLATE(RIGHT(theEntry,3))=":P." THEN
606 theEntry=theEntry||stripCommentChars(theLine)
607 ELSE
608 theEntry=theEntry||' '||stripCommentChars(theLine)
609 END
610 ELSE DO
611 theEntry=theEntry||' '||stripCommentChars(theLine)
612 END
613
614 END
615 theEntry=STRIP(theEntry)
616/*SAY '%%'||theEntry||'%%'*/
617 END
618return theEntry
619
620/********************************/
621/* Remove starting and ending */
622/* comment chars from arg. */
623/********************************/
624stripCommentChars:
625 theString=STRIP(SUBSTR(ARG(1),3))
626return STRIP(LEFT(theString, LENGTH(theString)-2))
627
628
629/********************************/
630/* Wrap a string over several lines by */
631/* inserting '0d'x'0a'x. */
632/********************************/
633wrapString:
634
635inString=ARG(1)
636numLines=TRUNC(LENGTH(inString)/80)
637DO widx = 1 to numlines
638 thePos=POS(' ',inString ,widx*80)
639 if thePos=0 THEN return inString
640 inString=INSERT('0d'x'0a'x, inString, thePos)
641END
642return inString
643
644
645
646
647
648
649
650 /* ------------------------------------------------------------------ */
651/* Author: Ruediger Wilke */
652 /* function: quick sort routine */
653 /* */
654 /* call: QuickSort first_element, last_element */
655 /* */
656 /* returns: nothing */
657 /* */
658 /* notes: You must save the elements to sort in the stem "a." */
659 /* a.0 must contain the number of elements in the stem. */
660 /* */
661 /* */
662 qqsort: procedure expose a.
663
664 arg lf, re
665
666 if re -lf < 9 then
667 do lf = lf to re -1
668
669 m = lf
670
671 do j = lf +1 to re
672 if TRANSLATE(a.j) << TRANSLATE(a.m) then /* v2.80 */
673 m = j
674 end /* j = lf +1 to re */
675
676 t = a.m; a.m = a.lf; a.lf = t
677
678 end /* lf = lf to re -1 */
679 else
680 do
681 i = lf
682 j = re
683 k = (lf + re)%2
684 t = TRANSLATE(a.k)
685
686 do until i > j
687
688 do while TRANSLATE(a.i) << t /* v2.80 + CW */
689 i = i + 1
690 end /* while a.i << t */
691
692 do while TRANSLATE(a.j) >> t /* v2.80 + CW */
693 j = j - 1
694 end /* while a.j >> t */
695
696 if i <= j then
697 do
698 xchg = a.i
699 a.i = a.j
700 a.j = xchg
701 i = i + 1
702 j = j - 1
703 end /* if i <= j then */
704
705 end /* until i > j */
706
707 call qqsort lf, j
708 call qqsort i, re
709 end /* else */
710
711 return
712
713
714
715
716
Note: See TracBrowser for help on using the repository browser.