| 1 | /* Create documentation for functions */
 | 
|---|
| 2 |  call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
 | 
|---|
| 3 |  call SysLoadFuncs
 | 
|---|
| 4 | 
 | 
|---|
| 5 | /* Set this to '1' to get debug messages */
 | 
|---|
| 6 | DEBUG=0
 | 
|---|
| 7 | 
 | 
|---|
| 8 | docInfo.=''
 | 
|---|
| 9 | 
 | 
|---|
| 10 | theDir=ARG(1)
 | 
|---|
| 11 | 
 | 
|---|
| 12 | IF theDir="" THEN theDir=STRIP(DIRECTORY())
 | 
|---|
| 13 | 
 | 
|---|
| 14 | /* Where to place the generated IPF source */
 | 
|---|
| 15 | docdir="r:\temp"
 | 
|---|
| 16 | ipf=docdir||'\CWTKDoc.ipf'            /* The IPF file        */
 | 
|---|
| 17 | 
 | 
|---|
| 18 | SAY "Base directory: "theDir
 | 
|---|
| 19 | SAY
 | 
|---|
| 20 | 
 | 
|---|
| 21 | /*** Read all the C files and parse them ***/
 | 
|---|
| 22 | SAY "Checking C files..."
 | 
|---|
| 23 | rc=SysFileTree(theDir"\*.c", "files.", "FSO")
 | 
|---|
| 24 | 
 | 
|---|
| 25 | IF 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 ""
 | 
|---|
| 31 | END
 | 
|---|
| 32 | 
 | 
|---|
| 33 | numLines=0
 | 
|---|
| 34 | index=0 /* This index holds the number of found descriptions */
 | 
|---|
| 35 | DO 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
 | 
|---|
| 51 | END
 | 
|---|
| 52 | 
 | 
|---|
| 53 | 
 | 
|---|
| 54 | IF files.0\=0 THEN DO
 | 
|---|
| 55 |         result._C=files.0
 | 
|---|
| 56 |         result._CLines=numLines
 | 
|---|
| 57 | END
 | 
|---|
| 58 | ELSE DO
 | 
|---|
| 59 |         result._C=0
 | 
|---|
| 60 |         result._CLines=0
 | 
|---|
| 61 | END
 | 
|---|
| 62 | 
 | 
|---|
| 63 | 
 | 
|---|
| 64 | SAY ""
 | 
|---|
| 65 | SAY result._Clines||" lines in "||result._c||" C files"
 | 
|---|
| 66 | 
 | 
|---|
| 67 | IF 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
 | 
|---|
| 77 | END
 | 
|---|
| 78 | 
 | 
|---|
| 79 | /*create docs */
 | 
|---|
| 80 | res=200                             /* The initial res id */
 | 
|---|
| 81 | leftWidth="30%"
 | 
|---|
| 82 | syntaxres=1                      /* Res id for syntax table. To be added to base. E.G. 201 */
 | 
|---|
| 83 | remarksres=2
 | 
|---|
| 84 | returnsres=3
 | 
|---|
| 85 | exampleres=4
 | 
|---|
| 86 | overrideres=5
 | 
|---|
| 87 | usageres=6
 | 
|---|
| 88 | paramsres=10
 | 
|---|
| 89 | 
 | 
|---|
| 90 | '@type NUL > 'ipf
 | 
|---|
| 91 | 
 | 
|---|
| 92 | /* Write IPF header */
 | 
|---|
| 93 | call writeIpfHeader ipf
 | 
|---|
| 94 | 
 | 
|---|
| 95 | /* Sort the function names in the array a. */
 | 
|---|
| 96 | a.=''
 | 
|---|
| 97 | DO b= 1 to index
 | 
|---|
| 98 |         a.b=STRIP(WORD(docinfo.b.function,2))
 | 
|---|
| 99 | END
 | 
|---|
| 100 | a.0=index
 | 
|---|
| 101 | call qqsort 1, index
 | 
|---|
| 102 | 
 | 
|---|
| 103 | IF 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
 | 
|---|
| 109 | END
 | 
|---|
| 110 | 
 | 
|---|
| 111 | /* Build a stem with the right order of indexes so in the document the functions are ordered */
 | 
|---|
| 112 | indStem.=''
 | 
|---|
| 113 | DO 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
 | 
|---|
| 120 | END
 | 
|---|
| 121 | 
 | 
|---|
| 122 | /* Write function reference */
 | 
|---|
| 123 | call writeIpfFunctionRef ipf
 | 
|---|
| 124 | 
 | 
|---|
| 125 | /* Footer */
 | 
|---|
| 126 | call writeIpfFooter ipf
 | 
|---|
| 127 | 
 | 
|---|
| 128 | call STREAM ipf, "C","close"
 | 
|---|
| 129 | 
 | 
|---|
| 130 | /* Compile the document */
 | 
|---|
| 131 | '@ipfc -i 'ipf
 | 
|---|
| 132 | 
 | 
|---|
| 133 | exit
 | 
|---|
| 134 | 
 | 
|---|
| 135 | /**************** Procedures *********************************/
 | 
|---|
| 136 | 
 | 
|---|
| 137 | writeIpfFunctionRef:
 | 
|---|
| 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
 | 
|---|
| 158 | return
 | 
|---|
| 159 | 
 | 
|---|
| 160 | /*********************/
 | 
|---|
| 161 | writeIpfFunction:
 | 
|---|
| 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."
 | 
|---|
| 170 | return
 | 
|---|
| 171 | 
 | 
|---|
| 172 | /*******************************************/
 | 
|---|
| 173 | /* Write the links in the left panel for   */
 | 
|---|
| 174 | /* this function.                                  */
 | 
|---|
| 175 | /*******************************************/
 | 
|---|
| 176 | writeIpfFuncLinks:
 | 
|---|
| 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
 | 
|---|
| 204 | return
 | 
|---|
| 205 | 
 | 
|---|
| 206 | /*********************************/
 | 
|---|
| 207 | /* Write the panel for the return value */
 | 
|---|
| 208 | /*********************************/
 | 
|---|
| 209 | writeIpfFuncReturns:
 | 
|---|
| 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))
 | 
|---|
| 222 | return
 | 
|---|
| 223 | 
 | 
|---|
| 224 | /*****************/
 | 
|---|
| 225 | writeIpfFuncOverride:
 | 
|---|
| 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 | 
 | 
|---|
| 237 | return
 | 
|---|
| 238 | 
 | 
|---|
| 239 | /*****************/
 | 
|---|
| 240 | writeIpfFuncUsage:
 | 
|---|
| 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 | 
 | 
|---|
| 252 | return
 | 
|---|
| 253 | 
 | 
|---|
| 254 | /*****************/
 | 
|---|
| 255 | writeIpfFuncParams:
 | 
|---|
| 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
 | 
|---|
| 291 | return
 | 
|---|
| 292 | 
 | 
|---|
| 293 | /*****************************/
 | 
|---|
| 294 | /* Write the Remarks panel          */
 | 
|---|
| 295 | /*****************************/
 | 
|---|
| 296 | writeIpfFuncRemarks:
 | 
|---|
| 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 | 
 | 
|---|
| 308 | return
 | 
|---|
| 309 | 
 | 
|---|
| 310 | /*****************/
 | 
|---|
| 311 | writeIpfFuncSyntax:
 | 
|---|
| 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, ""
 | 
|---|
| 365 | return
 | 
|---|
| 366 | 
 | 
|---|
| 367 | /***************************/
 | 
|---|
| 368 | writeIpfHeader: procedure expose res
 | 
|---|
| 369 | ipf=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..."
 | 
|---|
| 383 | return
 | 
|---|
| 384 | 
 | 
|---|
| 385 | /**************************/
 | 
|---|
| 386 | writeIpfFooter:
 | 
|---|
| 387 |         IF DEBUG=1 THEN
 | 
|---|
| 388 |                 SAY "DEBUG: Writing IPF footer..."
 | 
|---|
| 389 |         /* Footer */
 | 
|---|
| 390 |         call lineout ARG(1), ":euserdoc."
 | 
|---|
| 391 | return
 | 
|---|
| 392 | 
 | 
|---|
| 393 | 
 | 
|---|
| 394 | /*************************************/
 | 
|---|
| 395 | /* This proc removes the types from  */
 | 
|---|
| 396 | /* the function definition but keeps */
 | 
|---|
| 397 | /* the var names.                    */
 | 
|---|
| 398 | /*************************************/
 | 
|---|
| 399 | removeTypesFromFunc: 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 '**' */
 | 
|---|
| 418 | IF SUBSTR(theString, thePos2+1,1)='*' THEN DO
 | 
|---|
| 419 |         thePos2=thePos2+2
 | 
|---|
| 420 | END
 | 
|---|
| 421 |                 theString=LEFT(theString, thePos)||STRIP(subStr(theString, thePos2))
 | 
|---|
| 422 |                 thePos=POS(',', theString, thePos+1)
 | 
|---|
| 423 |         END
 | 
|---|
| 424 | return 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 | /*******************************/
 | 
|---|
| 434 | getFunctionName: procedure
 | 
|---|
| 435 |         func=ARG(1)
 | 
|---|
| 436 |         thePos=POS('(', func)
 | 
|---|
| 437 |         func=LEFT(func,thePos-1)
 | 
|---|
| 438 |         
 | 
|---|
| 439 | return 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 | /*******************************/
 | 
|---|
| 448 | getFunctionName2: 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 | /*******************************/
 | 
|---|
| 465 | parseFile: procedure expose (exposelist)
 | 
|---|
| 466 | 
 | 
|---|
| 467 | a=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
 | 
|---|
| 479 | return
 | 
|---|
| 480 | 
 | 
|---|
| 481 | /*******************************/
 | 
|---|
| 482 | /* Parse the whole comment block   */
 | 
|---|
| 483 | /* with information                         */
 | 
|---|
| 484 | /*******************************/
 | 
|---|
| 485 | parseComment: 
 | 
|---|
| 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
 | 
|---|
| 506 | return
 | 
|---|
| 507 | 
 | 
|---|
| 508 | /********************************/
 | 
|---|
| 509 | /* Read lines until a '{' is found.          */
 | 
|---|
| 510 | /* This means reading in a function    */
 | 
|---|
| 511 | /* declaration.                                 */
 | 
|---|
| 512 | /*                                                   */
 | 
|---|
| 513 | /*                                                   */
 | 
|---|
| 514 | /*                                                   */
 | 
|---|
| 515 | /********************************/
 | 
|---|
| 516 | 
 | 
|---|
| 517 | getCompleteFunction:
 | 
|---|
| 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
 | 
|---|
| 535 | return theLine
 | 
|---|
| 536 | 
 | 
|---|
| 537 | /*******************************/
 | 
|---|
| 538 | /* Parse entries starting with @@ in  */
 | 
|---|
| 539 | /* comment block.                          */
 | 
|---|
| 540 | /*******************************/
 | 
|---|
| 541 | parseEntry:
 | 
|---|
| 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
 | 
|---|
| 580 | return ""
 | 
|---|
| 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 | /************************************/
 | 
|---|
| 588 | readEntryContents:
 | 
|---|
| 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
 | 
|---|
| 618 | return theEntry
 | 
|---|
| 619 | 
 | 
|---|
| 620 | /********************************/
 | 
|---|
| 621 | /* Remove starting and ending           */
 | 
|---|
| 622 | /* comment chars from arg.               */
 | 
|---|
| 623 | /********************************/
 | 
|---|
| 624 | stripCommentChars:
 | 
|---|
| 625 |         theString=STRIP(SUBSTR(ARG(1),3))
 | 
|---|
| 626 | return STRIP(LEFT(theString, LENGTH(theString)-2))
 | 
|---|
| 627 | 
 | 
|---|
| 628 | 
 | 
|---|
| 629 | /********************************/
 | 
|---|
| 630 | /* Wrap a string over several lines by  */
 | 
|---|
| 631 | /* inserting '0d'x'0a'x.                        */
 | 
|---|
| 632 | /********************************/
 | 
|---|
| 633 | wrapString:
 | 
|---|
| 634 | 
 | 
|---|
| 635 | inString=ARG(1)
 | 
|---|
| 636 | numLines=TRUNC(LENGTH(inString)/80)
 | 
|---|
| 637 | DO 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)
 | 
|---|
| 641 | END
 | 
|---|
| 642 | return 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 | 
 | 
|---|