Mercurial > hg > octave-lyh
comparison src/help.cc @ 8575:f134925a1cfa
m-file implementation of help system
author | Soren Hauberg <soren@hauberg.org> |
---|---|
date | Thu, 22 Jan 2009 18:22:52 -0500 |
parents | 8ba2ee57c594 |
children | 540165304f00 |
comparison
equal
deleted
inserted
replaced
8574:83b8c739d626 | 8575:f134925a1cfa |
---|---|
84 | 84 |
85 // If TRUE, don't print additional help message in help and usage | 85 // If TRUE, don't print additional help message in help and usage |
86 // functions. | 86 // functions. |
87 static bool Vsuppress_verbose_help_message = false; | 87 static bool Vsuppress_verbose_help_message = false; |
88 | 88 |
89 // FIXME -- maybe this should use string instead of char*. | 89 #include <map> |
90 | 90 |
91 struct help_list | 91 typedef std::map<std::string, std::string> map_type; |
92 { | 92 typedef map_type::value_type pair_type; |
93 const char *name; | 93 typedef map_type::const_iterator map_iter; |
94 const char *help; | 94 |
95 }; | 95 template<typename T, std::size_t z> |
96 | 96 std::size_t |
97 static help_list operators[] = | 97 size (T const (&)[z]) |
98 { | 98 { |
99 { "!", | 99 return z; |
100 "Logical not operator. See also `~'.\n", }, | 100 } |
101 | 101 |
102 { "!=", | 102 // FIXME -- The descriptions could easily be in texinfo -- should they? |
103 "Logical not equals operator. See also `~' and `<>'.\n", }, | 103 const static pair_type operators[] = |
104 | 104 { |
105 { "\"", | 105 pair_type ("!", |
106 "String delimiter.\n", }, | 106 "Logical not operator. See also `~'.\n"), |
107 | 107 |
108 { "#", | 108 pair_type ("!=", |
109 "Begin comment character. See also `%'.", }, | 109 "Logical not equals operator. See also `~='.\n"), |
110 | 110 |
111 { "%", | 111 pair_type ("\"", |
112 "Begin comment charcter. See also `#'.", }, | 112 "String delimiter.\n"), |
113 | 113 |
114 { "&", | 114 pair_type ("#", |
115 "Logical and operator. See also `&&'.", }, | 115 "Begin comment character. See also `%'."), |
116 | 116 |
117 { "&&", | 117 pair_type ("%", |
118 "Logical and operator. See also `&'.", }, | 118 "Begin comment charcter. See also `#'."), |
119 | 119 |
120 { "'", | 120 pair_type ("&", |
121 "Element by element logical and operator. See also `&&'."), | |
122 | |
123 pair_type ("&&", | |
124 "Logical and operator (with short-circuit evaluation). See also `&'."), | |
125 | |
126 pair_type ("'", | |
121 "Matrix transpose operator. For complex matrices, computes the\n\ | 127 "Matrix transpose operator. For complex matrices, computes the\n\ |
122 complex conjugate (Hermitian) transpose. See also `.''\n\ | 128 complex conjugate (Hermitian) transpose. See also `.''\n\ |
123 \n\ | 129 \n\ |
124 The single quote character may also be used to delimit strings, but\n\ | 130 The single quote character may also be used to delimit strings, but\n\ |
125 it is better to use the double quote character, since that is never\n\ | 131 it is better to use the double quote character, since that is never\n\ |
126 ambiguous", }, | 132 ambiguous"), |
127 | 133 |
128 { "(", | 134 pair_type ("(", |
129 "Array index or function argument delimiter.", }, | 135 "Array index or function argument delimiter."), |
130 | 136 |
131 { ")", | 137 pair_type (")", |
132 "Array index or function argument delimiter.", }, | 138 "Array index or function argument delimiter."), |
133 | 139 |
134 { "*", | 140 pair_type ("*", |
135 "Multiplication operator. See also `.*'", }, | 141 "Multiplication operator. See also `.*'"), |
136 | 142 |
137 { "**", | 143 pair_type ("**", |
138 "Power operator. See also `^', `.**', and `.^'", }, | 144 "Power operator. See also `^', `.**', and `.^'"), |
139 | 145 |
140 { "+", | 146 pair_type ("+", |
141 "Addition operator.", }, | 147 "Addition operator."), |
142 | 148 |
143 { "++", | 149 pair_type ("++", |
144 "Increment operator. As in C, may be applied as a prefix or postfix\n\ | 150 "Increment operator. As in C, may be applied as a prefix or postfix\n\ |
145 operator.", }, | 151 operator."), |
146 | 152 |
147 { ",", | 153 pair_type (",", |
148 "Array index, function argument, or command separator.", }, | 154 "Array index, function argument, or command separator."), |
149 | 155 |
150 { "-", | 156 pair_type ("-", |
151 "Subtraction or unary negation operator.", }, | 157 "Subtraction or unary negation operator."), |
152 | 158 |
153 { "--", | 159 pair_type ("--", |
154 "Decrement operator. As in C, may be applied as a prefix or postfix\n\ | 160 "Decrement operator. As in C, may be applied as a prefix or postfix\n\ |
155 operator.", }, | 161 operator."), |
156 | 162 |
157 { ".'", | 163 pair_type (".'", |
158 "Matrix transpose operator. For complex matrices, computes the\n\ | 164 "Matrix transpose operator. For complex matrices, computes the\n\ |
159 transpose, *not* the complex conjugate transpose. See also `''.", }, | 165 transpose, *not* the complex conjugate transpose. See also `''."), |
160 | 166 |
161 { ".*", | 167 pair_type (".*", |
162 "Element by element multiplication operator. See also `*'.", }, | 168 "Element by element multiplication operator. See also `*'."), |
163 | 169 |
164 { ".**", | 170 pair_type (".**", |
165 "Element by element power operator. See also `**', `^', and `.^'.", }, | 171 "Element by element power operator. See also `**', `^', and `.^'."), |
166 | 172 |
167 { "./", | 173 pair_type ("./", |
168 "Element by element division operator. See also `/' and `\\'.", }, | 174 "Element by element division operator. See also `/' and `\\'."), |
169 | 175 |
170 { ".^", | 176 pair_type (".^", |
171 "Element by element power operator. See also `**', `^', and `.^'.", }, | 177 "Element by element power operator. See also `**', `^', and `.^'."), |
172 | 178 |
173 { "/", | 179 pair_type ("/", |
174 "Right division. See also `\\' and `./'.", }, | 180 "Right division. See also `\\' and `./'."), |
175 | 181 |
176 { ":", | 182 pair_type (":", |
177 "Select entire rows or columns of matrices.", }, | 183 "Select entire rows or columns of matrices."), |
178 | 184 |
179 { ";", | 185 pair_type (";", |
180 "Array row or command separator. See also `,'.", }, | 186 "Array row or command separator. See also `,'."), |
181 | 187 |
182 { "<", | 188 pair_type ("<", |
183 "Less than operator.", }, | 189 "Less than operator."), |
184 | 190 |
185 { "<=", | 191 pair_type ("<=", |
186 "Less than or equals operator.", }, | 192 "Less than or equals operator."), |
187 | 193 |
188 { "<>", | 194 pair_type ("=", |
189 "Logical not equals operator. See also `!=' and `~='.", }, | 195 "Assignment operator."), |
190 | 196 |
191 { "=", | 197 pair_type ("==", |
192 "Assignment operator.", }, | 198 "Equality test operator."), |
193 | 199 |
194 { "==", | 200 pair_type (">", |
195 "Equality test operator.", }, | 201 "Greater than operator."), |
196 | 202 |
197 { ">", | 203 pair_type (">=", |
198 "Greater than operator.", }, | 204 "Greater than or equals operator."), |
199 | 205 |
200 { ">=", | 206 pair_type ("[", |
201 "Greater than or equals operator.", }, | 207 "Return list delimiter. See also `]'."), |
202 | 208 |
203 { "[", | 209 pair_type ("\\", |
204 "Return list delimiter. See also `]'.", }, | 210 "Left division operator. See also `/' and `./'."), |
205 | 211 |
206 { "\\", | 212 pair_type ("]", |
207 "Left division operator. See also `/' and `./'.", }, | 213 "Return list delimiter. See also `['."), |
208 | 214 |
209 { "]", | 215 pair_type ("^", |
210 "Return list delimiter. See also `['.", }, | 216 "Power operator. See also `**', `.^', and `.**.'"), |
211 | 217 |
212 { "^", | 218 pair_type ("|", |
213 "Power operator. See also `**', `.^', and `.**.'", }, | 219 "Element by element logical or operator. See also `||'."), |
214 | 220 |
215 { "|", | 221 pair_type ("||", |
216 "Logical or operator. See also `||'.", }, | 222 "Logical or operator (with short-circuit evaluation). See also `|'."), |
217 | 223 |
218 { "||", | 224 pair_type ("~", |
219 "Logical or operator. See also `|'.", }, | 225 "Logical not operator. See also `!' and `~'."), |
220 | 226 |
221 { "~", | 227 pair_type ("~=", |
222 "Logical not operator. See also `!' and `~'.", }, | 228 "Logical not equals operator. See also `!='."), |
223 | |
224 { "~=", | |
225 "Logical not equals operator. See also `<>' and `!='.", }, | |
226 | |
227 { 0, 0, }, | |
228 }; | 229 }; |
229 | 230 |
230 static help_list keywords[] = | 231 const static pair_type keywords[] = |
231 { | 232 { |
232 { "break", | 233 pair_type ("break", |
233 "-*- texinfo -*-\n\ | 234 "-*- texinfo -*-\n\ |
234 @deffn Keyword break\n\ | 235 @deffn Keyword break\n\ |
235 Exit the innermost enclosing do, while or for loop.\n\ | 236 Exit the innermost enclosing do, while or for loop.\n\ |
236 @seealso{do, while, for, continue}\n\ | 237 @seealso{do, while, for, continue}\n\ |
237 @end deffn", }, | 238 @end deffn"), |
238 | 239 |
239 { "case", | 240 pair_type ("case", |
240 "-*- texinfo -*-\n\ | 241 "-*- texinfo -*-\n\ |
241 @deffn Keyword case @{@var{value}@}\n\ | 242 @deffn Keyword case @{@var{value}@}\n\ |
242 A case statement in an switch. Octave cases are exclusive and do not\n\ | 243 A case statement in an switch. Octave cases are exclusive and do not\n\ |
243 fall-through as do C-language cases. A switch statement must have at least\n\ | 244 fall-through as do C-language cases. A switch statement must have at least\n\ |
244 one case. See @code{switch} for an example.\n\ | 245 one case. See @code{switch} for an example.\n\ |
245 @seealso{switch}\n\ | 246 @seealso{switch}\n\ |
246 @end deffn", }, | 247 @end deffn"), |
247 | 248 |
248 { "catch", | 249 pair_type ("catch", |
249 "-*- texinfo -*-\n\ | 250 "-*- texinfo -*-\n\ |
250 @deffn Keyword catch\n\ | 251 @deffn Keyword catch\n\ |
251 Begin the cleanup part of a try-catch block.\n\ | 252 Begin the cleanup part of a try-catch block.\n\ |
252 @seealso{try}\n\ | 253 @seealso{try}\n\ |
253 @end deffn", }, | 254 @end deffn"), |
254 | 255 |
255 { "continue", | 256 pair_type ("continue", |
256 "-*- texinfo -*-\n\ | 257 "-*- texinfo -*-\n\ |
257 @deffn Keyword continue\n\ | 258 @deffn Keyword continue\n\ |
258 Jump to the end of the innermost enclosing do, while or for loop.\n\ | 259 Jump to the end of the innermost enclosing do, while or for loop.\n\ |
259 @seealso{do, while, for, break}\n\ | 260 @seealso{do, while, for, break}\n\ |
260 @end deffn", }, | 261 @end deffn"), |
261 | 262 |
262 { "do", | 263 pair_type ("do", |
263 "-*- texinfo -*-\n\ | 264 "-*- texinfo -*-\n\ |
264 @deffn Keyword do\n\ | 265 @deffn Keyword do\n\ |
265 Begin a do-until loop. This differs from a do-while loop in that the\n\ | 266 Begin a do-until loop. This differs from a do-while loop in that the\n\ |
266 body of the loop is executed at least once.\n\ | 267 body of the loop is executed at least once.\n\ |
267 @seealso{while}\n\ | 268 @seealso{while}\n\ |
268 @end deffn", }, | 269 @end deffn"), |
269 | 270 |
270 { "else", | 271 pair_type ("else", |
271 "-*- texinfo -*-\n\ | 272 "-*- texinfo -*-\n\ |
272 @deffn Keyword else\n\ | 273 @deffn Keyword else\n\ |
273 Alternate action for an if block. See @code{if} for an example.\n\ | 274 Alternate action for an if block. See @code{if} for an example.\n\ |
274 @seealso{if}\n\ | 275 @seealso{if}\n\ |
275 @end deffn", }, | 276 @end deffn"), |
276 | 277 |
277 { "elseif", | 278 pair_type ("elseif", |
278 "-*- texinfo -*-\n\ | 279 "-*- texinfo -*-\n\ |
279 @deffn Keyword elseif (@var{condition})\n\ | 280 @deffn Keyword elseif (@var{condition})\n\ |
280 Alternate conditional test for an if block. See @code{if} for an example.\n\ | 281 Alternate conditional test for an if block. See @code{if} for an example.\n\ |
281 @seealso{if}\n\ | 282 @seealso{if}\n\ |
282 @end deffn", }, | 283 @end deffn"), |
283 | 284 |
284 { "end", | 285 pair_type ("end", |
285 "-*- texinfo -*-\n\ | 286 "-*- texinfo -*-\n\ |
286 @deffn Keyword end\n\ | 287 @deffn Keyword end\n\ |
287 Mark the end of any @code{for}, @code{if}, @code{do}, @code{while}, or @code{function} block.\n\ | 288 Mark the end of any @code{for}, @code{if}, @code{do}, @code{while}, or @code{function} block.\n\ |
288 @seealso{for, if, do, while, function}\n\ | 289 @seealso{for, if, do, while, function}\n\ |
289 @end deffn", }, | 290 @end deffn"), |
290 | 291 |
291 { "end_try_catch", | 292 pair_type ("end_try_catch", |
292 "-*- texinfo -*-\n\ | 293 "-*- texinfo -*-\n\ |
293 @deffn Keyword end_try_catch\n\ | 294 @deffn Keyword end_try_catch\n\ |
294 Mark the end of an @code{try-catch} block.\n\ | 295 Mark the end of an @code{try-catch} block.\n\ |
295 @seealso{try, catch}\n\ | 296 @seealso{try, catch}\n\ |
296 @end deffn", }, | 297 @end deffn"), |
297 | 298 |
298 { "end_unwind_protect", | 299 pair_type ("end_unwind_protect", |
299 "-*- texinfo -*-\n\ | 300 "-*- texinfo -*-\n\ |
300 @deffn Keyword end_unwind_protect\n\ | 301 @deffn Keyword end_unwind_protect\n\ |
301 Mark the end of an unwind_protect block.\n\ | 302 Mark the end of an unwind_protect block.\n\ |
302 @seealso{unwind_protect}\n\ | 303 @seealso{unwind_protect}\n\ |
303 @end deffn", }, | 304 @end deffn"), |
304 | 305 |
305 { "endfor", | 306 pair_type ("endfor", |
306 "-*- texinfo -*-\n\ | 307 "-*- texinfo -*-\n\ |
307 @deffn Keyword endfor\n\ | 308 @deffn Keyword endfor\n\ |
308 Mark the end of a for loop. See @code{for} for an example.\n\ | 309 Mark the end of a for loop. See @code{for} for an example.\n\ |
309 @seealso{for}\n\ | 310 @seealso{for}\n\ |
310 @end deffn", }, | 311 @end deffn"), |
311 | 312 |
312 { "endfunction", | 313 pair_type ("endfunction", |
313 "-*- texinfo -*-\n\ | 314 "-*- texinfo -*-\n\ |
314 @deffn Keyword endfunction\n\ | 315 @deffn Keyword endfunction\n\ |
315 Mark the end of a function.\n\ | 316 Mark the end of a function.\n\ |
316 @seealso{function}\n\ | 317 @seealso{function}\n\ |
317 @end deffn", }, | 318 @end deffn"), |
318 | 319 |
319 { "endif", | 320 pair_type ("endif", |
320 "-*- texinfo -*-\n\ | 321 "-*- texinfo -*-\n\ |
321 @deffn Keyword endif\n\ | 322 @deffn Keyword endif\n\ |
322 Mark the end of an if block. See @code{if} for an example.\n\ | 323 Mark the end of an if block. See @code{if} for an example.\n\ |
323 @seealso{if}\n\ | 324 @seealso{if}\n\ |
324 @end deffn", }, | 325 @end deffn"), |
325 | 326 |
326 { "endswitch", | 327 pair_type ("endswitch", |
327 "-*- texinfo -*-\n\ | 328 "-*- texinfo -*-\n\ |
328 @deffn Keyword endswitch\n\ | 329 @deffn Keyword endswitch\n\ |
329 Mark the end of a switch block. See @code{switch} for an example.\n\ | 330 Mark the end of a switch block. See @code{switch} for an example.\n\ |
330 @seealso{switch}\n\ | 331 @seealso{switch}\n\ |
331 @end deffn", }, | 332 @end deffn"), |
332 | 333 |
333 { "endwhile", | 334 pair_type ("endwhile", |
334 "-*- texinfo -*-\n\ | 335 "-*- texinfo -*-\n\ |
335 @deffn Keyword endwhile\n\ | 336 @deffn Keyword endwhile\n\ |
336 Mark the end of a while loop. See @code{while} for an example.\n\ | 337 Mark the end of a while loop. See @code{while} for an example.\n\ |
337 @seealso{do, while}\n\ | 338 @seealso{do, while}\n\ |
338 @end deffn", }, | 339 @end deffn"), |
339 | 340 |
340 { "for", | 341 pair_type ("for", |
341 "-*- texinfo -*-\n\ | 342 "-*- texinfo -*-\n\ |
342 @deffn Keyword for @var{i} = @var{range}\n\ | 343 @deffn Keyword for @var{i} = @var{range}\n\ |
343 Begin a for loop.\n\ | 344 Begin a for loop.\n\ |
344 @example\n\ | 345 @example\n\ |
345 for i = 1:10\n\ | 346 for i = 1:10\n\ |
346 i\n\ | 347 i\n\ |
347 endfor\n\ | 348 endfor\n\ |
348 @end example\n\ | 349 @end example\n\ |
349 @seealso{do, while}\n\ | 350 @seealso{do, while}\n\ |
350 @end deffn", }, | 351 @end deffn"), |
351 | 352 |
352 { "function", | 353 pair_type ("function", |
353 "-*- texinfo -*-\n\ | 354 "-*- texinfo -*-\n\ |
354 @deffn Keyword function @var{outputs} = function (@var{input}, ...)\n\ | 355 @deffn Keyword function @var{outputs} = function (@var{input}, ...)\n\ |
355 @deffnx Keyword function {} function (@var{input}, ...)\n\ | 356 @deffnx Keyword function {} function (@var{input}, ...)\n\ |
356 @deffnx Keyword function @var{outputs} = function\n\ | 357 @deffnx Keyword function @var{outputs} = function\n\ |
357 Begin a function body with @var{outputs} as results and @var{inputs} as\n\ | 358 Begin a function body with @var{outputs} as results and @var{inputs} as\n\ |
358 parameters.\n\ | 359 parameters.\n\ |
359 @seealso{return}\n\ | 360 @seealso{return}\n\ |
360 @end deffn", }, | 361 @end deffn"), |
361 | 362 |
362 { "global", | 363 pair_type ("global", |
363 "-*- texinfo -*-\n\ | 364 "-*- texinfo -*-\n\ |
364 @deffn Keyword global\n\ | 365 @deffn Keyword global\n\ |
365 Declare variables to have global scope.\n\ | 366 Declare variables to have global scope.\n\ |
366 @example\n\ | 367 @example\n\ |
367 global @var{x};\n\ | 368 global @var{x};\n\ |
368 if isempty (@var{x})\n\ | 369 if isempty (@var{x})\n\ |
369 x = 1;\n\ | 370 x = 1;\n\ |
370 endif\n\ | 371 endif\n\ |
371 @end example\n\ | 372 @end example\n\ |
372 @seealso{persistent}\n\ | 373 @seealso{persistent}\n\ |
373 @end deffn", }, | 374 @end deffn"), |
374 | 375 |
375 { "if", | 376 pair_type ("if", |
376 "-*- texinfo -*-\n\ | 377 "-*- texinfo -*-\n\ |
377 @deffn Keyword if (@var{cond}) @dots{} endif\n\ | 378 @deffn Keyword if (@var{cond}) @dots{} endif\n\ |
378 @deffnx Keyword if (@var{cond}) @dots{} else @dots{} endif\n\ | 379 @deffnx Keyword if (@var{cond}) @dots{} else @dots{} endif\n\ |
379 @deffnx Keyword if (@var{cond}) @dots{} elseif (@var{cond}) @dots{} endif\n\ | 380 @deffnx Keyword if (@var{cond}) @dots{} elseif (@var{cond}) @dots{} endif\n\ |
380 @deffnx Keyword if (@var{cond}) @dots{} elseif (@var{cond}) @dots{} else @dots{} endif\n\ | 381 @deffnx Keyword if (@var{cond}) @dots{} elseif (@var{cond}) @dots{} else @dots{} endif\n\ |
388 else\n\ | 389 else\n\ |
389 disp (\"not one or two\");\n\ | 390 disp (\"not one or two\");\n\ |
390 endif\n\ | 391 endif\n\ |
391 @end example\n\ | 392 @end example\n\ |
392 @seealso{switch}\n\ | 393 @seealso{switch}\n\ |
393 @end deffn", }, | 394 @end deffn"), |
394 | 395 |
395 { "otherwise", | 396 pair_type ("otherwise", |
396 "-*- texinfo -*-\n\ | 397 "-*- texinfo -*-\n\ |
397 @deffn Keyword otherwise\n\ | 398 @deffn Keyword otherwise\n\ |
398 The default statement in a switch block (similar to else in an if block).\n\ | 399 The default statement in a switch block (similar to else in an if block).\n\ |
399 @seealso{switch}\n\ | 400 @seealso{switch}\n\ |
400 @end deffn", }, | 401 @end deffn"), |
401 | 402 |
402 { "persistent", | 403 pair_type ("persistent", |
403 "-*- texinfo -*-\n\ | 404 "-*- texinfo -*-\n\ |
404 @deffn Keyword persistent @var{var}\n\ | 405 @deffn Keyword persistent @var{var}\n\ |
405 Declare variables as persistent. A variable that has been declared\n\ | 406 Declare variables as persistent. A variable that has been declared\n\ |
406 persistent within a function will retain its contents in memory between\n\ | 407 persistent within a function will retain its contents in memory between\n\ |
407 subsequent calls to the same function. The difference between persistent\n\ | 408 subsequent calls to the same function. The difference between persistent\n\ |
408 variables and global variables is that persistent variables are local in \n\ | 409 variables and global variables is that persistent variables are local in \n\ |
409 scope to a particular function and are not visible elsewhere.\n\ | 410 scope to a particular function and are not visible elsewhere.\n\ |
410 @seealso{global}\n\ | 411 @seealso{global}\n\ |
411 @end deffn", }, | 412 @end deffn"), |
412 | 413 |
413 { "replot", | 414 pair_type ("replot", |
414 "-*- texinfo -*-\n\ | 415 "-*- texinfo -*-\n\ |
415 @deffn Keyword replot\n\ | 416 @deffn Keyword replot\n\ |
416 Replot a graphic.\n\ | 417 Replot a graphic.\n\ |
417 @seealso{plot}\n\ | 418 @seealso{plot}\n\ |
418 @end deffn", }, | 419 @end deffn"), |
419 | 420 |
420 { "return", | 421 pair_type ("return", |
421 "-*- texinfo -*-\n\ | 422 "-*- texinfo -*-\n\ |
422 @deffn Keyword return\n\ | 423 @deffn Keyword return\n\ |
423 Return from a function.\n\ | 424 Return from a function.\n\ |
424 @seealso{function}\n\ | 425 @seealso{function}\n\ |
425 @end deffn", }, | 426 @end deffn"), |
426 | 427 |
427 { "static", | 428 pair_type ("static", |
428 "-*- texinfo -*-\n\ | 429 "-*- texinfo -*-\n\ |
429 @deffn Keyword static\n\ | 430 @deffn Keyword static\n\ |
430 This function has been deprecated in favor of persistent.\n\ | 431 This function has been deprecated in favor of persistent.\n\ |
431 @seealso{persistent}\n\ | 432 @seealso{persistent}\n\ |
432 @end deffn", }, | 433 @end deffn"), |
433 | 434 |
434 { "switch", | 435 pair_type ("switch", |
435 "-*- texinfo -*-\n\ | 436 "-*- texinfo -*-\n\ |
436 @deffn Keyword switch @var{statement}\n\ | 437 @deffn Keyword switch @var{statement}\n\ |
437 Begin a switch block.\n\ | 438 Begin a switch block.\n\ |
438 @example\n\ | 439 @example\n\ |
439 yesno = \"yes\"\n\ | 440 yesno = \"yes\"\n\ |
446 otherwise\n\ | 447 otherwise\n\ |
447 error (\"invalid value\");\n\ | 448 error (\"invalid value\");\n\ |
448 endswitch\n\ | 449 endswitch\n\ |
449 @end example\n\ | 450 @end example\n\ |
450 @seealso{if, case, otherwise}\n\ | 451 @seealso{if, case, otherwise}\n\ |
451 @end deffn", }, | 452 @end deffn"), |
452 | 453 |
453 { "try", | 454 pair_type ("try", |
454 "-*- texinfo -*-\n\ | 455 "-*- texinfo -*-\n\ |
455 @deffn Keyword try\n\ | 456 @deffn Keyword try\n\ |
456 Begin a try-catch block.\n\ | 457 Begin a try-catch block.\n\ |
457 \n\ | 458 \n\ |
458 If an error occurs within a try block, then the catch code will be run and\n\ | 459 If an error occurs within a try block, then the catch code will be run and\n\ |
459 execution will proceed after the catch block (though it is often\n\ | 460 execution will proceed after the catch block (though it is often\n\ |
460 recommended to use the lasterr function to re-throw the error after cleanup\n\ | 461 recommended to use the lasterr function to re-throw the error after cleanup\n\ |
461 is completed).\n\ | 462 is completed).\n\ |
462 @seealso{catch,unwind_protect}\n\ | 463 @seealso{catch,unwind_protect}\n\ |
463 @end deffn", }, | 464 @end deffn"), |
464 | 465 |
465 { "until", | 466 pair_type ("until", |
466 "-*- texinfo -*-\n\ | 467 "-*- texinfo -*-\n\ |
467 @deffn Keyword until\n\ | 468 @deffn Keyword until\n\ |
468 End a do-until loop.\n\ | 469 End a do-until loop.\n\ |
469 @seealso{do}\n\ | 470 @seealso{do}\n\ |
470 @end deffn", }, | 471 @end deffn"), |
471 | 472 |
472 { "unwind_protect", | 473 pair_type ("unwind_protect", |
473 "-*- texinfo -*-\n\ | 474 "-*- texinfo -*-\n\ |
474 @deffn Keyword unwind_protect\n\ | 475 @deffn Keyword unwind_protect\n\ |
475 Begin an unwind_protect block.\n\ | 476 Begin an unwind_protect block.\n\ |
476 \n\ | 477 \n\ |
477 If an error occurs within the first part of an unwind_protect block\n\ | 478 If an error occurs within the first part of an unwind_protect block\n\ |
479 the error is thrown. If an error is not thrown, then the\n\ | 480 the error is thrown. If an error is not thrown, then the\n\ |
480 unwind_protect_cleanup block is still executed (in other words, the\n\ | 481 unwind_protect_cleanup block is still executed (in other words, the\n\ |
481 unwind_protect_cleanup will be run with or without an error in the\n\ | 482 unwind_protect_cleanup will be run with or without an error in the\n\ |
482 unwind_protect block).\n\ | 483 unwind_protect block).\n\ |
483 @seealso{unwind_protect_cleanup,try}\n\ | 484 @seealso{unwind_protect_cleanup,try}\n\ |
484 @end deffn", }, | 485 @end deffn"), |
485 | 486 |
486 { "unwind_protect_cleanup", | 487 pair_type ("unwind_protect_cleanup", |
487 "-*- texinfo -*-\n\ | 488 "-*- texinfo -*-\n\ |
488 @deffn Keyword unwind_protect_cleanup\n\ | 489 @deffn Keyword unwind_protect_cleanup\n\ |
489 Begin the cleanup section of an unwind_protect block.\n\ | 490 Begin the cleanup section of an unwind_protect block.\n\ |
490 @seealso{unwind_protect}\n\ | 491 @seealso{unwind_protect}\n\ |
491 @end deffn", }, | 492 @end deffn"), |
492 | 493 |
493 { "varargin", | 494 pair_type ("varargin", |
494 "-*- texinfo -*-\n\ | 495 "-*- texinfo -*-\n\ |
495 @deffn Keyword varargin\n\ | 496 @deffn Keyword varargin\n\ |
496 Pass an arbitrary number of arguments into a function.\n\ | 497 Pass an arbitrary number of arguments into a function.\n\ |
497 @seealso{varargout, nargin, nargout}\n\ | 498 @seealso{varargout, nargin, nargout}\n\ |
498 @end deffn", }, | 499 @end deffn"), |
499 | 500 |
500 { "varargout", | 501 pair_type ("varargout", |
501 "-*- texinfo -*-\n\ | 502 "-*- texinfo -*-\n\ |
502 @deffn Keyword varargout\n\ | 503 @deffn Keyword varargout\n\ |
503 Pass an arbitrary number of arguments out of a function.\n\ | 504 Pass an arbitrary number of arguments out of a function.\n\ |
504 @seealso{varargin, nargin, nargout}\n\ | 505 @seealso{varargin, nargin, nargout}\n\ |
505 @end deffn", }, | 506 @end deffn"), |
506 | 507 |
507 { "while", | 508 pair_type ("while", |
508 "-*- texinfo -*-\n\ | 509 "-*- texinfo -*-\n\ |
509 @deffn Keyword while\n\ | 510 @deffn Keyword while\n\ |
510 Begin a while loop.\n\ | 511 Begin a while loop.\n\ |
511 @seealso{do}\n\ | 512 @seealso{do}\n\ |
512 @end deffn", }, | 513 @end deffn"), |
513 | |
514 { 0, 0, }, | |
515 }; | 514 }; |
516 | 515 |
517 // Return a copy of the operator or keyword names. | 516 // Return a copy of the operator or keyword names. |
518 | |
519 static string_vector | 517 static string_vector |
520 names (help_list *lst) | 518 names (const map_type& lst) |
521 { | 519 { |
522 string_vector retval; | 520 string_vector retval (lst.size ()); |
523 | 521 int j = 0; |
524 int count = 0; | 522 for (map_iter iter = lst.begin (); iter != lst.end (); iter ++) |
525 help_list *ptr = lst; | 523 retval [j++] = iter->first; |
526 while (ptr->name) | |
527 { | |
528 count++; | |
529 ptr++; | |
530 } | |
531 | |
532 if (count > 0) | |
533 { | |
534 retval.resize (count); | |
535 | |
536 ptr = lst; | |
537 for (int i = 0; i < count; i++) | |
538 { | |
539 retval[i] = ptr->name; | |
540 ptr++; | |
541 } | |
542 } | |
543 | |
544 return retval; | 524 return retval; |
545 } | 525 } |
546 | 526 |
547 static help_list * | 527 const static map_type operators_map (operators, operators + size (operators)); |
548 operator_help (void) | 528 const static map_type keywords_map (keywords, keywords + size (keywords)); |
549 { | 529 const static string_vector keyword_names = names (keywords_map); |
550 return operators; | 530 |
551 } | 531 // FIXME -- It's not likely that this does the right thing now. |
552 | |
553 static help_list * | |
554 keyword_help (void) | |
555 { | |
556 return keywords; | |
557 } | |
558 | |
559 // It's not likely that this does the right thing now. FIXME | |
560 | 532 |
561 string_vector | 533 string_vector |
562 make_name_list (void) | 534 make_name_list (void) |
563 { | 535 { |
564 string_vector key = names (keyword_help ()); | 536 const int key_len = keyword_names.length (); |
565 int key_len = key.length (); | 537 |
566 | 538 const string_vector bif = symbol_table::built_in_function_names (); |
567 string_vector bif = symbol_table::built_in_function_names (); | 539 const int bif_len = bif.length (); |
568 int bif_len = bif.length (); | |
569 | 540 |
570 // FIXME -- is this really necessary here? | 541 // FIXME -- is this really necessary here? |
571 string_vector glb = symbol_table::global_variable_names (); | 542 const string_vector glb = symbol_table::global_variable_names (); |
572 int glb_len = glb.length (); | 543 const int glb_len = glb.length (); |
573 | 544 |
574 // FIXME -- is this really necessary here? | 545 // FIXME -- is this really necessary here? |
575 string_vector top = symbol_table::top_level_variable_names (); | 546 const string_vector top = symbol_table::top_level_variable_names (); |
576 int top_len = top.length (); | 547 const int top_len = top.length (); |
577 | 548 |
578 string_vector lcl; | 549 string_vector lcl; |
579 if (! symbol_table::at_top_level ()) | 550 if (! symbol_table::at_top_level ()) |
580 lcl = symbol_table::variable_names (); | 551 lcl = symbol_table::variable_names (); |
581 int lcl_len = lcl.length (); | 552 const int lcl_len = lcl.length (); |
582 | 553 |
583 string_vector ffl = load_path::fcn_names (); | 554 const string_vector ffl = load_path::fcn_names (); |
584 int ffl_len = ffl.length (); | 555 const int ffl_len = ffl.length (); |
585 | 556 |
586 string_vector afl = autoloaded_functions (); | 557 const string_vector afl = autoloaded_functions (); |
587 int afl_len = afl.length (); | 558 const int afl_len = afl.length (); |
588 | 559 |
589 int total_len = key_len + bif_len + glb_len + top_len + lcl_len | 560 const int total_len = key_len + bif_len + glb_len + top_len + lcl_len |
590 + ffl_len + afl_len; | 561 + ffl_len + afl_len; |
591 | 562 |
592 string_vector list (total_len); | 563 string_vector list (total_len); |
593 | 564 |
594 // Put all the symbols in one big list. | 565 // Put all the symbols in one big list. |
595 | 566 |
596 int j = 0; | 567 int j = 0; |
597 int i = 0; | 568 int i = 0; |
598 for (i = 0; i < key_len; i++) | 569 for (i = 0; i < key_len; i++) |
599 list[j++] = key[i]; | 570 list[j++] = keyword_names[i]; |
600 | 571 |
601 for (i = 0; i < bif_len; i++) | 572 for (i = 0; i < bif_len; i++) |
602 list[j++] = bif[i]; | 573 list[j++] = bif[i]; |
603 | 574 |
604 for (i = 0; i < glb_len; i++) | 575 for (i = 0; i < glb_len; i++) |
617 list[j++] = afl[i]; | 588 list[j++] = afl[i]; |
618 | 589 |
619 return list; | 590 return list; |
620 } | 591 } |
621 | 592 |
622 void | 593 static bool |
623 additional_help_message (std::ostream& os) | 594 looks_like_html (const std::string& msg) |
624 { | 595 { |
625 if (! Vsuppress_verbose_help_message) | 596 const size_t p1 = msg.find ('\n'); |
626 os << "\ | 597 std::string t = msg.substr (0, p1); |
627 Additional help for built-in functions and operators is\n\ | 598 const size_t p2 = t.find ("<html"); // FIXME: this comparison should be case-insensitive |
628 available in the on-line version of the manual. Use the command\n\ | 599 |
629 `doc <topic>' to search the manual index.\n\ | 600 return (p2 != std::string::npos); |
630 \n\ | |
631 Help and information about Octave is also available on the WWW\n\ | |
632 at http://www.octave.org and via the help@octave.org\n\ | |
633 mailing list.\n"; | |
634 } | |
635 | |
636 // FIXME -- this needs a major overhaul to cope with new | |
637 // symbol table stuff. | |
638 | |
639 static void | |
640 display_names_from_help_list (std::ostream& os, help_list *list, | |
641 const char *desc) | |
642 { | |
643 string_vector symbols = names (list); | |
644 | |
645 if (! symbols.empty ()) | |
646 { | |
647 os << "\n*** " << desc << ":\n\n"; | |
648 | |
649 symbols.sort (); | |
650 | |
651 symbols.list_in_columns (os); | |
652 } | |
653 } | |
654 | |
655 static void | |
656 display_symtab_names (std::ostream& os, const std::list<std::string>& names, | |
657 const std::string& desc) | |
658 { | |
659 if (! names.empty ()) | |
660 { | |
661 os << "\n*** " << desc << ":\n\n"; | |
662 | |
663 string_vector sv (names); | |
664 | |
665 sv.list_in_columns (os); | |
666 } | |
667 } | |
668 | |
669 static void | |
670 simple_help (void) | |
671 { | |
672 octave_stdout << "Help is available for the topics listed below.\n"; | |
673 | |
674 additional_help_message (octave_stdout); | |
675 | |
676 display_names_from_help_list (octave_stdout, operator_help (), | |
677 "operators"); | |
678 | |
679 display_names_from_help_list (octave_stdout, keyword_help (), | |
680 "reserved words"); | |
681 | |
682 display_symtab_names (octave_stdout, | |
683 symbol_table::built_in_function_names (), | |
684 "built-in functions"); | |
685 | |
686 // FIXME -- list functions defined on command line? | |
687 | |
688 load_path::display (octave_stdout); | |
689 | |
690 string_vector autoloaded = autoloaded_functions (); | |
691 | |
692 if (! autoloaded.empty ()) | |
693 { | |
694 octave_stdout << "\n*** autoloaded functions:\n\n"; | |
695 | |
696 autoloaded.sort (); | |
697 | |
698 autoloaded.list_in_columns (octave_stdout); | |
699 } | |
700 } | |
701 | |
702 static int | |
703 try_info (const std::string& nm) | |
704 { | |
705 int retval = -1; | |
706 | |
707 warning ("please use `doc' instead of `help -i'"); | |
708 | |
709 octave_value_list args; | |
710 args(0) = nm; | |
711 octave_value_list result = feval ("doc", args, 1); | |
712 | |
713 if (result.length () > 0) | |
714 retval = result(0).int_value (); | |
715 | |
716 return retval; | |
717 } | |
718 | |
719 static void | |
720 help_from_info (const string_vector& argv, int idx, int argc) | |
721 { | |
722 if (idx == argc) | |
723 try_info (std::string ()); | |
724 else | |
725 { | |
726 for (int i = idx; i < argc; i++) | |
727 { | |
728 int status = try_info (argv[i]); | |
729 | |
730 if (status == 127) | |
731 break; | |
732 else if (status != 0) | |
733 message ("help", "`%s' is not indexed in the manual", | |
734 argv[i].c_str ()); | |
735 } | |
736 } | |
737 } | 601 } |
738 | 602 |
739 static bool | 603 static bool |
740 looks_like_texinfo (const std::string& msg, size_t& p1) | 604 looks_like_texinfo (const std::string& msg, size_t& p1) |
741 { | 605 { |
747 p1 = 0; | 611 p1 = 0; |
748 | 612 |
749 size_t p2 = t.find ("-*- texinfo -*-"); | 613 size_t p2 = t.find ("-*- texinfo -*-"); |
750 | 614 |
751 return (p2 != std::string::npos); | 615 return (p2 != std::string::npos); |
752 } | |
753 | |
754 void | |
755 display_help_text (std::ostream& os, const std::string& msg) | |
756 { | |
757 // Look for "-*- texinfo -*-" in first line of help message. If it | |
758 // is present, use makeinfo to format the rest of the message before | |
759 // sending it to the output stream. Otherwise, just print the | |
760 // message. | |
761 | |
762 size_t pos; | |
763 | |
764 if (looks_like_texinfo (msg, pos)) | |
765 { | |
766 os.flush (); | |
767 | |
768 std::string tmp_file_name = file_ops::tempnam ("", ""); | |
769 | |
770 int cols = command_editor::terminal_cols (); | |
771 | |
772 if (cols > 16) | |
773 cols--; | |
774 | |
775 if (cols > 64) | |
776 cols -= 7; | |
777 | |
778 if (cols > 80) | |
779 cols = 72; | |
780 | |
781 std::ostringstream buf; | |
782 | |
783 // Use double quotes to quote the sed patterns for Windows. | |
784 | |
785 buf << "sed -e \"s/^[#%][#%]* *//\" -e \"s/^ *@/@/\" | " | |
786 << "\"" << Vmakeinfo_program << "\"" | |
787 << " -D \"VERSION " << OCTAVE_VERSION << "\"" | |
788 << " -D \"OCTAVEHOME " << OCTAVE_PREFIX << "\"" | |
789 << " -D \"TARGETHOSTTYPE " << OCTAVE_CANONICAL_HOST_TYPE << "\"" | |
790 << " --fill-column " << cols | |
791 << " --no-warn" | |
792 << " --no-validate" | |
793 << " --no-headers" | |
794 << " --force" | |
795 << " --output \"" << tmp_file_name << "\""; | |
796 | |
797 oprocstream filter (buf.str ()); | |
798 | |
799 if (filter && filter.is_open ()) | |
800 { | |
801 filter << "@macro seealso {args}\n" | |
802 << "@sp 1\n" | |
803 << "@noindent\n" | |
804 << "See also: \\args\\.\n" | |
805 << "@end macro\n"; | |
806 | |
807 filter << msg.substr (pos+1) << std::endl; | |
808 | |
809 int status = filter.close (); | |
810 | |
811 std::ifstream tmp_file (tmp_file_name.c_str ()); | |
812 | |
813 if (WIFEXITED (status) && WEXITSTATUS (status) == 0) | |
814 { | |
815 int c; | |
816 while ((c = tmp_file.get ()) != EOF) | |
817 os << (char) c; | |
818 | |
819 tmp_file.close (); | |
820 } | |
821 else | |
822 { | |
823 warning ("help: Texinfo formatting filter exited abnormally"); | |
824 warning ("help: raw Texinfo source of help text follows..."); | |
825 warning ("help:\n\n%s\n\n", msg.c_str ()); | |
826 } | |
827 | |
828 file_ops::unlink (tmp_file_name); | |
829 } | |
830 else | |
831 os << msg; | |
832 } | |
833 else | |
834 os << msg; | |
835 } | |
836 | |
837 void | |
838 display_usage_text (std::ostream& os, const std::string& msg) | |
839 { | |
840 std::string filtered_msg = msg; | |
841 | |
842 size_t pos; | |
843 | |
844 if (looks_like_texinfo (msg, pos)) | |
845 { | |
846 std::ostringstream buf; | |
847 | |
848 buf << "-*- texinfo -*-\n"; | |
849 | |
850 bool found_def = false; | |
851 | |
852 size_t msg_len = msg.length (); | |
853 | |
854 while (pos < msg_len) | |
855 { | |
856 size_t new_pos = msg.find_first_of ('\n', pos); | |
857 | |
858 if (new_pos == std::string::npos) | |
859 new_pos = msg_len-1; | |
860 | |
861 std::string line = msg.substr (pos, new_pos-pos+1); | |
862 | |
863 if (line.substr (0, 4) == "@def" | |
864 || line.substr (0, 8) == "@end def") | |
865 { | |
866 found_def = true; | |
867 buf << line; | |
868 } | |
869 | |
870 pos = new_pos + 1; | |
871 } | |
872 | |
873 if (found_def) | |
874 filtered_msg = buf.str (); | |
875 } | |
876 | |
877 display_help_text (os, filtered_msg); | |
878 } | |
879 | |
880 static bool | |
881 raw_help_from_list (const help_list *list, const std::string& nm, | |
882 std::string& h, bool& symbol_found) | |
883 { | |
884 bool retval = false; | |
885 | |
886 const char *name; | |
887 | |
888 while ((name = list->name) != 0) | |
889 { | |
890 if (strcmp (name, nm.c_str ()) == 0) | |
891 { | |
892 symbol_found = true; | |
893 | |
894 h = list->help; | |
895 | |
896 if (h.length () > 0) | |
897 retval = true; | |
898 | |
899 break; | |
900 } | |
901 list++; | |
902 } | |
903 | |
904 return retval;; | |
905 } | |
906 | |
907 static bool | |
908 help_from_list (std::ostream& os, const help_list *list, | |
909 const std::string& nm, int usage, bool& symbol_found) | |
910 { | |
911 bool retval = false; | |
912 | |
913 std::string h; | |
914 | |
915 if (raw_help_from_list (list, nm, h, symbol_found)) | |
916 { | |
917 if (h.length () > 0) | |
918 { | |
919 if (usage) | |
920 os << "\nusage: "; | |
921 else | |
922 os << "\n*** " << nm << ":\n\n"; | |
923 | |
924 display_help_text (os, h); | |
925 | |
926 os << "\n"; | |
927 | |
928 retval = true; | |
929 } | |
930 } | |
931 | |
932 return retval; | |
933 } | 616 } |
934 | 617 |
935 static bool | 618 static bool |
936 raw_help_from_symbol_table (const std::string& nm, std::string& h, | 619 raw_help_from_symbol_table (const std::string& nm, std::string& h, |
937 std::string& w, bool& symbol_found) | 620 std::string& w, bool& symbol_found) |
958 | 641 |
959 if (w.empty ()) | 642 if (w.empty ()) |
960 w = fcn->is_user_function () | 643 w = fcn->is_user_function () |
961 ? "command-line function" : "built-in function"; | 644 ? "command-line function" : "built-in function"; |
962 } | 645 } |
963 } | |
964 } | |
965 | |
966 return retval; | |
967 } | |
968 | |
969 static bool | |
970 help_from_symbol_table (std::ostream& os, const std::string& nm, | |
971 bool& symbol_found) | |
972 { | |
973 bool retval = false; | |
974 | |
975 std::string h; | |
976 std::string w; | |
977 | |
978 if (raw_help_from_symbol_table (nm, h, w, symbol_found)) | |
979 { | |
980 if (h.length () > 0) | |
981 { | |
982 std::string dispatch_help = symbol_table::help_for_dispatch (nm); | |
983 | |
984 if (! dispatch_help.empty ()) | |
985 { | |
986 size_t pos = 0; | |
987 | |
988 std::string pfx = looks_like_texinfo (h, pos) | |
989 ? std::string ("\n\n@noindent\n") : std::string ("\n\n"); | |
990 | |
991 h += pfx + dispatch_help; | |
992 } | |
993 | |
994 display_help_text (os, h); | |
995 | |
996 if (w.length () > 0 && ! Vsuppress_verbose_help_message) | |
997 os << w << "\n"; | |
998 | |
999 os << "\n"; | |
1000 | |
1001 retval = true; | |
1002 } | 646 } |
1003 } | 647 } |
1004 | 648 |
1005 return retval; | 649 return retval; |
1006 } | 650 } |
1030 | 674 |
1031 return retval; | 675 return retval; |
1032 } | 676 } |
1033 | 677 |
1034 static bool | 678 static bool |
1035 help_from_file (std::ostream& os, const std::string& nm, bool& symbol_found) | 679 raw_help_from_map (const std::string& nm, std::string& h, |
1036 { | 680 const map_type& map, bool& symbol_found) |
1037 bool retval = false; | 681 { |
1038 | 682 map_iter idx = map.find (nm); |
1039 std::string h; | 683 symbol_found = (idx != map.end ()); |
1040 std::string file; | 684 h = (symbol_found) ? idx->second : ""; |
1041 | 685 return symbol_found; |
1042 if (raw_help_from_file (nm, h, file, symbol_found)) | |
1043 { | |
1044 if (h.length () > 0) | |
1045 { | |
1046 // Strip extension | |
1047 size_t l = file.length (); | |
1048 if (l > 2 && file.substr (l-2) == ".m") | |
1049 { | |
1050 std::string tmp = file.substr (0, l - 2); | |
1051 | |
1052 if (file_stat (tmp + ".oct")) | |
1053 file = tmp + ".oct"; | |
1054 else if (file_stat (tmp + ".mex")) | |
1055 file = tmp + ".mex"; | |
1056 } | |
1057 | |
1058 os << nm << " is the file " << file << "\n\n"; | |
1059 | |
1060 display_help_text (os, h); | |
1061 | |
1062 os << "\n"; | |
1063 | |
1064 retval = true; | |
1065 } | |
1066 } | |
1067 | |
1068 return retval; | |
1069 } | 686 } |
1070 | 687 |
1071 std::string | 688 std::string |
1072 raw_help (const std::string& nm, bool &symbol_found) | 689 raw_help (const std::string& nm, bool& symbol_found) |
1073 { | 690 { |
1074 std::string h; | 691 std::string h; |
1075 std::string w; | 692 std::string w; |
1076 std::string f; | 693 std::string f; |
1077 | 694 |
1078 (raw_help_from_list (operator_help (), nm, h, symbol_found) | 695 (raw_help_from_symbol_table (nm, h, w, symbol_found) |
1079 || raw_help_from_list (keyword_help (), nm, h, symbol_found) | 696 || raw_help_from_file (nm, h, f, symbol_found) |
1080 || raw_help_from_symbol_table (nm, h, w, symbol_found) | 697 || raw_help_from_map (nm, h, operators_map, symbol_found) |
1081 || raw_help_from_file (nm, h, f, symbol_found)); | 698 || raw_help_from_map (nm, h, keywords_map, symbol_found)); |
1082 | 699 |
1083 return h; | 700 return h; |
1084 } | 701 } |
1085 | 702 |
1086 static void | 703 static void |
1087 builtin_help (int argc, const string_vector& argv) | 704 do_get_help_text (const std::string name, std::string& text, |
1088 { | 705 std::string& format) |
1089 help_list *op_help_list = operator_help (); | 706 { |
1090 help_list *kw_help_list = keyword_help (); | 707 bool symbol_found = false; |
1091 | 708 text = raw_help (name, symbol_found); |
1092 for (int i = 1; i < argc; i++) | 709 |
710 format = "Not found"; | |
711 if (symbol_found) | |
1093 { | 712 { |
1094 bool symbol_found = false; | 713 size_t idx = -1; |
1095 | 714 if (looks_like_texinfo (text, idx)) |
1096 if (help_from_list (octave_stdout, op_help_list, argv[i], 0, | 715 { |
1097 symbol_found)) | 716 format = "texinfo"; |
1098 continue; | 717 text.erase (0, idx); |
1099 | 718 } |
1100 if (help_from_list (octave_stdout, kw_help_list, argv[i], 0, | 719 else if (looks_like_html (text)) |
1101 symbol_found)) | 720 { |
1102 continue; | 721 format = "html"; |
1103 | 722 } |
1104 if (help_from_symbol_table (octave_stdout, argv[i], symbol_found)) | 723 else |
1105 continue; | 724 { |
1106 | 725 format = "plain text"; |
1107 if (error_state) | 726 } |
727 } | |
728 } | |
729 | |
730 DEFUN (get_help_text, args, , "-*- texinfo -*-\n\ | |
731 @deftypefn {Loadable Function} {[@var{text}, @var{format}] =} get_help_text (@var{name})\n\ | |
732 Returns the help text of a given function.\n\ | |
733 \n\ | |
734 This function returns the raw help text @var{text} and an indication of\n\ | |
735 its format for the function @var{name}. The format indication @var{format}\n\ | |
736 is a string that can be either @t{\"texinfo\"}, @t{\"html\"}, or\n\ | |
737 @t{\"plain text\"}.\n\ | |
738 \n\ | |
739 To convert the help text to other formats, use the @code{makeinfo} function.\n\ | |
740 \n\ | |
741 @seealso{makeinfo}\n\ | |
742 @end deftypefn\n") | |
743 { | |
744 octave_value_list retval; | |
745 | |
746 if (args.length () == 1) | |
747 { | |
748 const std::string name = args (0).string_value (); | |
749 | |
750 if (! error_state) | |
1108 { | 751 { |
1109 octave_stdout << "\n"; | 752 std::string text; |
1110 error_state = 0; | 753 std::string format; |
1111 continue; | 754 |
755 do_get_help_text (name, text, format); | |
756 | |
757 retval(1) = format; | |
758 retval(0) = text; | |
1112 } | 759 } |
1113 | |
1114 if (help_from_file (octave_stdout, argv[i], symbol_found)) | |
1115 continue; | |
1116 | |
1117 if (error_state) | |
1118 { | |
1119 octave_stdout << "\n"; | |
1120 error_state = 0; | |
1121 continue; | |
1122 } | |
1123 | |
1124 if (symbol_found) | |
1125 octave_stdout << "\nhelp: `" << argv[i] | |
1126 << "' is not documented\n"; | |
1127 else | 760 else |
1128 octave_stdout << "\nhelp: `" << argv[i] | 761 error ("get_help_text: invalid input"); |
1129 << "' not found\n"; | |
1130 } | |
1131 | |
1132 additional_help_message (octave_stdout); | |
1133 } | |
1134 | |
1135 DEFCMD (help, args, , | |
1136 "-*- texinfo -*-\n\ | |
1137 @deffn {Command} help @var{name}\n\ | |
1138 Display the help text for @var{name}.\n\ | |
1139 If invoked without any arguments, @code{help} prints a list\n\ | |
1140 of all the available operators and functions.\n\ | |
1141 \n\ | |
1142 For example, the command @kbd{help help} prints a short message\n\ | |
1143 describing the @code{help} command.\n\ | |
1144 \n\ | |
1145 The help command can give you information about operators, but not the\n\ | |
1146 comma and semicolons that are used as command separators. To get help\n\ | |
1147 for those, you must type @kbd{help comma} or @kbd{help semicolon}.\n\ | |
1148 @seealso{doc, which, lookfor}\n\ | |
1149 @end deffn") | |
1150 { | |
1151 octave_value_list retval; | |
1152 | |
1153 int argc = args.length () + 1; | |
1154 | |
1155 string_vector argv = args.make_argv ("help"); | |
1156 | |
1157 if (error_state) | |
1158 return retval; | |
1159 | |
1160 if (argc == 1) | |
1161 simple_help (); | |
1162 else | |
1163 { | |
1164 if (argv[1] == "-i") | |
1165 help_from_info (argv, 2, argc); | |
1166 else | |
1167 builtin_help (argc, argv); | |
1168 } | |
1169 | |
1170 return retval; | |
1171 } | |
1172 | |
1173 static void | |
1174 display_file (std::ostream& os, const std::string& name, | |
1175 const std::string& fname, const std::string& type, | |
1176 bool pr_type_info, bool quiet) | |
1177 { | |
1178 std::ifstream fs (fname.c_str (), std::ios::in); | |
1179 | |
1180 if (fs) | |
1181 { | |
1182 if (pr_type_info && ! quiet) | |
1183 os << name << " is the " << type << " defined from the file\n" | |
1184 << fname << ":\n\n"; | |
1185 | |
1186 char ch; | |
1187 | |
1188 while (fs.get (ch)) | |
1189 os << ch; | |
1190 } | 762 } |
1191 else | 763 else |
1192 os << "unable to open `" << fname << "' for reading!\n"; | 764 print_usage (); |
1193 } | 765 |
1194 | 766 return retval; |
1195 static void | 767 } |
1196 do_type (std::ostream& os, const std::string& name, bool pr_type_info, | 768 |
1197 bool quiet, bool pr_orig_txt) | 769 DEFUN (__operators__, , , "-*- texinfo -*-\n\ |
1198 { | 770 @deftypefn {Function File} __operators__ ()\n\ |
1199 // FIXME -- should we bother with variables here (earlier versions | 771 Return a cell array of strings containing the names of all operators.\n\ |
1200 // of Octave displayed them)? | 772 \n\ |
1201 | 773 This is an internal function and should not be used directly.\n\ |
1202 octave_value val = symbol_table::varval (name); | 774 @end deftypefn\n") |
775 { | |
776 return octave_value (Cell (names (operators_map))); | |
777 } | |
778 | |
779 DEFUN (__keywords__, , , "-*- texinfo -*-\n\ | |
780 @deftypefn {Function File} __keywords__ ()\n\ | |
781 Return a cell array of strings containing the names of all keywords.\n\ | |
782 \n\ | |
783 This is an internal function and should not be used directly.\n\ | |
784 @end deftypefn\n") | |
785 { | |
786 return octave_value (Cell (names (keywords_map))); | |
787 } | |
788 | |
789 DEFUN (__builtins__, , , "-*- texinfo -*-\n\ | |
790 @deftypefn {Function File} __builtins__ ()\n\ | |
791 Return a cell array of strings containing the names of all builtin functions.\n\ | |
792 \n\ | |
793 This is an internal function and should not be used directly.\n\ | |
794 @end deftypefn\n") | |
795 { | |
796 const string_vector bif = symbol_table::built_in_function_names (); | |
797 | |
798 return octave_value (Cell (bif)); | |
799 } | |
800 | |
801 static std::string | |
802 do_which (const std::string& name, std::string& type) | |
803 { | |
804 std::string file; | |
805 | |
806 type = std::string (); | |
807 | |
808 octave_value val = symbol_table::find_function (name); | |
1203 | 809 |
1204 if (val.is_defined ()) | 810 if (val.is_defined ()) |
1205 { | 811 { |
1206 if (pr_type_info && ! quiet) | 812 octave_function *fcn = val.function_value (); |
1207 os << name << " is a variable\n"; | 813 |
1208 | 814 if (fcn) |
1209 val.print_raw (os, pr_orig_txt); | |
1210 | |
1211 if (pr_type_info) | |
1212 os << "\n"; | |
1213 } | |
1214 else | |
1215 { | |
1216 val = symbol_table::find_function (name); | |
1217 | |
1218 if (val.is_defined ()) | |
1219 { | 815 { |
1220 octave_function *fcn = val.function_value (); | 816 file = fcn->fcn_file_name (); |
1221 | 817 |
1222 if (fcn) | 818 if (file.empty ()) |
1223 { | 819 { |
1224 std::string fn = fcn->fcn_file_name (); | 820 if (fcn->is_user_function ()) |
1225 | 821 type = "command-line function"; |
1226 if (fcn->is_builtin_function ()) | |
1227 os << name << " is a built-in function" << std::endl; | |
1228 else if (fcn->is_dld_function () || fcn->is_mex_function ()) | |
1229 os << name | |
1230 << " is a dyanmically loaded function from the file\n" | |
1231 << fn << std::endl; | |
1232 else if (pr_orig_txt && ! fn.empty ()) | |
1233 display_file (os, name, fn, | |
1234 val.is_user_script () ? "script" : "function", | |
1235 pr_type_info, quiet); | |
1236 else | 822 else |
1237 { | 823 type = "built-in function"; |
1238 if (pr_type_info && ! quiet) | |
1239 { | |
1240 os << name; | |
1241 | |
1242 if (fcn->is_user_function ()) | |
1243 { | |
1244 if (fn.empty ()) | |
1245 os << " is a command-line function:\n\n"; | |
1246 else | |
1247 os << " is a " | |
1248 << (val.is_user_script () | |
1249 ? std::string ("script") | |
1250 : std::string ("function")) | |
1251 << " defined from the file\n" | |
1252 << fn << ":\n\n"; | |
1253 } | |
1254 } | |
1255 | |
1256 tree_print_code tpc (os, "", pr_orig_txt); | |
1257 | |
1258 fcn->accept (tpc); | |
1259 } | |
1260 } | 824 } |
825 else | |
826 type = val.is_user_script () | |
827 ? std::string ("script") : std::string ("function"); | |
1261 } | 828 } |
1262 } | 829 } |
1263 } | 830 |
1264 | 831 return file; |
1265 DEFCMD (type, args, nargout, | 832 } |
833 | |
834 std::string | |
835 do_which (const std::string& name) | |
836 { | |
837 std::string retval; | |
838 | |
839 std::string type; | |
840 | |
841 retval = do_which (name, type); | |
842 | |
843 return retval; | |
844 } | |
845 | |
846 DEFUN (__which__, args, , | |
1266 "-*- texinfo -*-\n\ | 847 "-*- texinfo -*-\n\ |
1267 \n\ | 848 @deftypefn {Built-in Function} {} __which__ (@var{name}, @dots{})\n\ |
1268 @deffn {Command} type options name @dots{}\n\ | 849 Undocumented internal function.\n\ |
1269 Display the definition of each @var{name} that refers to a function.\n\ | 850 @end deftypefn") |
1270 \n\ | |
1271 Normally also displays whether each @var{name} is user-defined or built-in;\n\ | |
1272 the @code{-q} option suppresses this behaviour.\n\ | |
1273 @end deffn") | |
1274 { | 851 { |
1275 octave_value retval; | 852 octave_value retval; |
1276 | 853 |
1277 int argc = args.length () + 1; | 854 string_vector argv = args.make_argv ("which"); |
1278 | |
1279 string_vector argv = args.make_argv ("type"); | |
1280 | 855 |
1281 if (! error_state) | 856 if (! error_state) |
1282 { | 857 { |
858 int argc = argv.length (); | |
859 | |
1283 if (argc > 1) | 860 if (argc > 1) |
1284 { | 861 { |
1285 // FIXME -- we should really use getopt () | 862 Octave_map m (dim_vector (1, argc-1)); |
1286 | 863 |
1287 bool quiet = false; | 864 Cell names (1, argc-1); |
1288 bool pr_orig_txt = true; | 865 Cell files (1, argc-1); |
1289 | 866 Cell types (1, argc-1); |
1290 int idx; | 867 |
1291 | 868 for (int i = 1; i < argc; i++) |
1292 for (idx = 1; idx < argc; idx++) | |
1293 { | 869 { |
1294 if (argv[idx] == "-q" || argv[idx] == "-quiet") | 870 std::string name = argv[i]; |
1295 quiet = true; | 871 |
1296 else if (argv[idx] == "-t" || argv[idx] == "-transformed") | 872 std::string type; |
1297 pr_orig_txt = false; | 873 |
1298 else | 874 std::string file = do_which (name, type); |
1299 break; | 875 |
876 names(i-1) = name; | |
877 files(i-1) = file; | |
878 types(i-1) = type; | |
1300 } | 879 } |
1301 | 880 |
1302 if (idx < argc) | 881 m.assign ("name", names); |
1303 { | 882 m.assign ("file", files); |
1304 std::ostringstream output_buf; | 883 m.assign ("type", types); |
1305 | 884 |
1306 for (int i = idx; i < argc; i++) | 885 retval = m; |
1307 { | |
1308 std::string id = argv[i]; | |
1309 | |
1310 if (nargout == 0) | |
1311 do_type (octave_stdout, id, true, quiet, pr_orig_txt); | |
1312 else | |
1313 do_type (output_buf, id, false, quiet, pr_orig_txt); | |
1314 | |
1315 if (error_state) | |
1316 goto abort; | |
1317 } | |
1318 | |
1319 if (nargout != 0) | |
1320 retval = output_buf.str (); | |
1321 } | |
1322 else | |
1323 print_usage (); | |
1324 } | 886 } |
1325 else | 887 else |
1326 print_usage (); | 888 print_usage (); |
1327 } | 889 } |
1328 | 890 |
1329 abort: | |
1330 | |
1331 return retval; | 891 return retval; |
1332 } | 892 } |
1333 | 893 |
1334 std::string | 894 // FIXME -- Are we sure this function always does the right thing? |
1335 do_which (const std::string& name) | 895 inline bool |
1336 { | 896 file_is_in_dir (const std::string filename, const std::string dir) |
1337 std::string retval; | 897 { |
1338 | 898 if (filename.find (dir) == 0) |
1339 octave_value val = symbol_table::find_function (name); | |
1340 | |
1341 if (val.is_defined ()) | |
1342 { | 899 { |
1343 octave_function *fcn = val.function_value (); | 900 const int dir_len = dir.size (); |
1344 | 901 const int filename_len = filename.size (); |
1345 if (fcn) | 902 const int max_allowed_seps = file_ops::is_dir_sep (dir [dir_len-1]) ? 0 : 1; |
1346 { | 903 |
1347 std::string fn = fcn->fcn_file_name (); | 904 int num_seps = 0; |
1348 | 905 for (int i = dir_len; i < filename_len; i++) |
1349 retval = fn.empty () | 906 if (file_ops::is_dir_sep (filename [i])) |
1350 ? (fcn->is_user_function () | 907 num_seps ++; |
1351 ? "command-line function" : "built-in function") | 908 |
1352 : fn; | 909 return (num_seps <= max_allowed_seps); |
1353 } | |
1354 } | 910 } |
1355 | 911 else |
1356 return retval; | 912 return false; |
1357 } | 913 } |
1358 | 914 |
1359 static void | 915 DEFUN (__list_functions__, args, , "-*- texinfo -*-\n\ |
1360 do_which (std::ostream& os, const std::string& name) | 916 @deftypefn {Function File} {@var{retval} =} __list_functions__ ()\n\ |
1361 { | 917 @deftypefnx{Function File} {@var{retval} =} __list_functions__ (@var{directory})\n\ |
1362 std::string desc; | 918 Return the functions available in a given directory.\n\ |
1363 | 919 \n\ |
1364 octave_value val = symbol_table::find_function (name); | 920 The function returns a cell array of strings containing the names of all\n\ |
1365 | 921 functions available in said directory. If no directory is given, the current\n\ |
1366 if (val.is_defined ()) | 922 path is searched.\n\ |
923 \n\ | |
924 This is an internal function and should not be used directly.\n\ | |
925 @seealso{path}\n\ | |
926 @end deftypefn\n") | |
927 { | |
928 octave_value_list retval; | |
929 | |
930 // Get list of functions | |
931 const string_vector ffl = load_path::fcn_names (); | |
932 const int ffl_len = ffl.length (); | |
933 const string_vector afl = autoloaded_functions (); | |
934 const int afl_len = afl.length (); | |
935 | |
936 if (args.length () == 0) | |
1367 { | 937 { |
1368 octave_function *fcn = val.function_value (); | 938 Cell C (ffl_len + afl_len, 1); |
1369 | 939 int j = 0; |
1370 if (fcn) | 940 for (int i = 0; i < ffl_len; i++) |
1371 { | 941 C (j++, 0) = octave_value (ffl [i]); |
1372 desc = fcn->fcn_file_name (); | 942 for (int i = 0; i < afl_len; i++) |
1373 | 943 C (j++, 0) = octave_value (afl [i]); |
1374 if (desc.empty ()) | 944 |
1375 { | 945 retval.append (octave_value (C)); |
1376 if (fcn->is_user_function ()) | |
1377 desc = "is a command-line function"; | |
1378 else | |
1379 desc = "is a built-in function"; | |
1380 } | |
1381 else | |
1382 desc = "is the " | |
1383 + (val.is_user_script () | |
1384 ? std::string ("script") : std::string ("function")) | |
1385 + " from the file " + desc; | |
1386 } | |
1387 | |
1388 os << "which: `" << name << "' " << desc << std::endl; | |
1389 } | |
1390 } | |
1391 | |
1392 DEFCMD (which, args, nargout, | |
1393 "-*- texinfo -*-\n\ | |
1394 @deffn {Command} which name @dots{}\n\ | |
1395 Display the type of each @var{name}. If @var{name} is defined from a\n\ | |
1396 function file, the full name of the file is also displayed.\n\ | |
1397 @seealso{help, lookfor}\n\ | |
1398 @end deffn") | |
1399 { | |
1400 octave_value_list retval; | |
1401 | |
1402 string_vector argv = args.make_argv ("which"); | |
1403 | |
1404 if (! error_state) | |
1405 { | |
1406 int argc = argv.length (); | |
1407 | |
1408 if (nargout > 0) | |
1409 retval.resize (argc-1, Matrix ()); | |
1410 | |
1411 if (argc > 1) | |
1412 { | |
1413 for (int i = 1; i < argc; i++) | |
1414 { | |
1415 std::string id = argv[i]; | |
1416 | |
1417 if (nargout == 0) | |
1418 do_which (octave_stdout, id); | |
1419 else | |
1420 retval(i-1) = do_which (id); | |
1421 } | |
1422 } | |
1423 else | |
1424 print_usage (); | |
1425 } | |
1426 | |
1427 return retval; | |
1428 } | |
1429 | |
1430 // FIXME | |
1431 // This function attempts to find the first sentence of a help string, though | |
1432 // given that the user can create the help in an arbitrary format, your | |
1433 // success might vary.. it works much better with help string formated in | |
1434 // texinfo. Using regex might make this function much simpler. | |
1435 | |
1436 std::string | |
1437 first_help_sentence (const std::string& h, bool short_sentence = true) | |
1438 { | |
1439 std::string retval; | |
1440 | |
1441 size_t pos = 0; | |
1442 | |
1443 if (looks_like_texinfo (h, pos)) | |
1444 { | |
1445 // Get the parsed help string. | |
1446 pos = 0; | |
1447 std::ostringstream os; | |
1448 display_help_text (os, h); | |
1449 std::string h2 = os.str (); | |
1450 | |
1451 while (1) | |
1452 { | |
1453 // Skip leading whitespace and get new line | |
1454 pos = h2.find_first_not_of ("\n\t ", pos); | |
1455 | |
1456 if (pos == std::string::npos) | |
1457 break; | |
1458 | |
1459 size_t new_pos = h2.find_first_of ('\n', pos); | |
1460 std::string line = h2.substr (pos, new_pos-pos); | |
1461 | |
1462 // Skip lines starting in "-" | |
1463 if (line.find_first_of ('-') == 0) | |
1464 { | |
1465 pos = new_pos + 1; | |
1466 continue; | |
1467 } | |
1468 | |
1469 break; | |
1470 } | |
1471 | |
1472 if (pos == std::string::npos) | |
1473 return retval; | |
1474 | |
1475 // At start of real text. Get first line with the sentence | |
1476 size_t new_pos = h2.find_first_of ('\n', pos); | |
1477 std::string line = h2.substr (pos, new_pos-pos); | |
1478 size_t dot_pos; | |
1479 | |
1480 while ((dot_pos = line.find_first_of ('.')) == std::string::npos) | |
1481 { | |
1482 // Trim trailing blanks on line | |
1483 line.substr (0, line.find_last_not_of ("\n\t ") + 1); | |
1484 | |
1485 // Append next line | |
1486 size_t tmp_pos = h2.find_first_not_of ("\n\t ", new_pos + 1); | |
1487 if (tmp_pos == std::string::npos || h2.substr (tmp_pos, 1) == "\n") | |
1488 break; | |
1489 | |
1490 new_pos = h2.find_first_of ('\n', tmp_pos); | |
1491 std::string next = h2.substr (tmp_pos, new_pos-tmp_pos); | |
1492 | |
1493 if (short_sentence) | |
1494 { | |
1495 if ((tmp_pos = next.find_first_of ('.')) != std::string::npos) | |
1496 { | |
1497 line = line + " " + next; | |
1498 dot_pos = line.find_first_of ('.'); | |
1499 } | |
1500 break; | |
1501 } | |
1502 else | |
1503 line = line + " " + next; | |
1504 } | |
1505 | |
1506 if (dot_pos == std::string::npos) | |
1507 retval = line; | |
1508 else | |
1509 retval = line.substr (0, dot_pos + 1); | |
1510 } | 946 } |
1511 else | 947 else |
1512 { | 948 { |
1513 std::string _upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | 949 // Get input |
1514 std::string _lower = "abcdefghijklmnopqrstuvwxyz"; | 950 std::string dir = args (0).string_value (); |
1515 std::string _alpha = _upper + _lower + "_"; | 951 if (error_state) |
1516 std::string _alphanum = _alpha + "1234567890"; | 952 error ("__list_functions__: input must be a string"); |
1517 pos = 0; | |
1518 | |
1519 while (1) | |
1520 { | |
1521 // Skip leading whitespace and get new line | |
1522 pos = h.find_first_not_of ("\n\t ", pos); | |
1523 | |
1524 if (pos == std::string::npos) | |
1525 break; | |
1526 | |
1527 size_t new_pos = h.find_first_of ('\n', pos); | |
1528 std::string line = h.substr (pos, new_pos-pos); | |
1529 | |
1530 // Make a lower case copy to simplify some tests | |
1531 std::string lower = line; | |
1532 std::transform (lower.begin (), lower.end (), lower.begin (), tolower); | |
1533 | |
1534 // Skip lines starting in "-" or "Usage" | |
1535 if (lower.find_first_of ('-') == 0 | |
1536 || lower.substr (0, 5) == "usage") | |
1537 { | |
1538 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1539 continue; | |
1540 } | |
1541 | |
1542 size_t line_pos = 0; | |
1543 size_t tmp_pos = 0; | |
1544 | |
1545 // chop " blah : " | |
1546 tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of | |
1547 (_alphanum, line_pos)); | |
1548 if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == ":") | |
1549 line_pos = line.find_first_not_of ("\t ", tmp_pos + 1); | |
1550 | |
1551 if (line_pos == std::string::npos) | |
1552 { | |
1553 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1554 continue; | |
1555 } | |
1556 | |
1557 // chop " function " | |
1558 if (lower.substr (line_pos, 8) == "function") | |
1559 line_pos = line.find_first_not_of ("\t ", line_pos + 8); | |
1560 | |
1561 if (line_pos == std::string::npos) | |
1562 { | |
1563 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1564 continue; | |
1565 } | |
1566 | |
1567 // chop " [a,b] = " | |
1568 if (line.substr (line_pos, 1) == "[") | |
1569 { | |
1570 tmp_pos = line.find_first_not_of | |
1571 ("\t ", line.find_first_of ("]", line_pos) + 1); | |
1572 | |
1573 if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "=") | |
1574 line_pos = line.find_first_not_of ("\t ",tmp_pos + 1); | |
1575 } | |
1576 | |
1577 if (line_pos == std::string::npos) | |
1578 { | |
1579 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1580 continue; | |
1581 } | |
1582 | |
1583 // chop " a = " | |
1584 if (line.find_first_not_of (_alpha, line_pos) != line_pos) | |
1585 { | |
1586 tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of | |
1587 (_alphanum, line_pos)); | |
1588 if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "=") | |
1589 line_pos = line.find_first_not_of ("\t ", tmp_pos + 1); | |
1590 } | |
1591 | |
1592 if (line_pos == std::string::npos) | |
1593 { | |
1594 pos = new_pos + 1; | |
1595 continue; | |
1596 } | |
1597 | |
1598 // chop " f(x) " | |
1599 if (line.find_first_not_of (_alpha, line_pos) != line_pos) | |
1600 { | |
1601 tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of | |
1602 (_alphanum, line_pos)); | |
1603 if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "(") | |
1604 line_pos = line.find_first_not_of ("\t ", line.find_first_of | |
1605 (")", tmp_pos) + 1); | |
1606 } | |
1607 | |
1608 if (line_pos == std::string::npos) | |
1609 { | |
1610 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1611 continue; | |
1612 } | |
1613 | |
1614 // chop " ; " | |
1615 if (line.substr (line_pos, 1) == ":" | |
1616 || line.substr (line_pos, 1) == ";") | |
1617 line_pos = line.find_first_not_of ("\t ", line_pos + 1); | |
1618 | |
1619 if (line_pos == std::string::npos) | |
1620 { | |
1621 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1622 continue; | |
1623 } | |
1624 | |
1625 // chop " BLAH " | |
1626 if (line.length () > line_pos + 2 | |
1627 && line.find_first_of (_upper, line_pos) == line_pos | |
1628 && line.find_first_of (_upper, line_pos+1) == line_pos + 1) | |
1629 line_pos = line.find_first_not_of ("\t ", line.find_first_not_of | |
1630 (_upper + "0123456789_", line_pos)); | |
1631 | |
1632 if (line_pos == std::string::npos) | |
1633 { | |
1634 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1635 continue; | |
1636 } | |
1637 | |
1638 // chop " blah --- " | |
1639 tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of | |
1640 (_alphanum, line_pos)); | |
1641 if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "-") | |
1642 { | |
1643 tmp_pos = line.find_first_not_of ("-", tmp_pos); | |
1644 if (line.substr (tmp_pos, 1) == " " | |
1645 || line.substr (tmp_pos, 1) == "\t") | |
1646 line_pos = line.find_first_not_of ("\t ", tmp_pos); | |
1647 } | |
1648 | |
1649 if (line_pos == std::string::npos) | |
1650 { | |
1651 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1652 continue; | |
1653 } | |
1654 | |
1655 // chop " blah <TAB> " | |
1656 if (line.find_first_not_of (_alpha, line_pos) != line_pos) | |
1657 { | |
1658 tmp_pos = line.find_first_not_of (" ", line.find_first_not_of | |
1659 (_alphanum, line_pos)); | |
1660 if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "\t") | |
1661 line_pos = line.find_first_not_of ("\t ", line.find_first_of | |
1662 (")", tmp_pos) + 1); | |
1663 } | |
1664 | |
1665 if (line_pos == std::string::npos) | |
1666 { | |
1667 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1668 continue; | |
1669 } | |
1670 | |
1671 // chop " blah " | |
1672 if (line.find_first_not_of (_alpha, line_pos) != line_pos) | |
1673 { | |
1674 tmp_pos = line.find_first_not_of (_alphanum, line_pos); | |
1675 | |
1676 if (tmp_pos != std::string::npos | |
1677 && (line.substr (tmp_pos, 2) == "\t\t" | |
1678 || line.substr (tmp_pos, 2) == "\t " | |
1679 || line.substr (tmp_pos, 2) == " \t" | |
1680 || line.substr (tmp_pos, 2) == " ")) | |
1681 line_pos = line.find_first_not_of ("\t ", tmp_pos); | |
1682 } | |
1683 | |
1684 if (line_pos == std::string::npos) | |
1685 { | |
1686 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1687 continue; | |
1688 } | |
1689 | |
1690 // skip blah \n or \n blah | |
1691 // skip blank line | |
1692 // skip "# !/usr/bin/octave" | |
1693 if ((line.substr (line_pos , 2) == "or" | |
1694 && line.find_first_not_of ("\n\t ", line_pos + 2) == std::string::npos) | |
1695 || line.find_first_not_of ("\n\t ", line_pos) == std::string::npos | |
1696 || line.substr (line_pos, 2) == "!/") | |
1697 { | |
1698 pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1); | |
1699 continue; | |
1700 } | |
1701 | |
1702 // Got the start of first sentence, break. | |
1703 pos = pos + line_pos; | |
1704 break; | |
1705 } | |
1706 | |
1707 if (pos == std::string::npos) | |
1708 return retval; | |
1709 | |
1710 // At start of real text. Get first line with the sentence | |
1711 size_t new_pos = h.find_first_of ('\n', pos); | |
1712 std::string line = h.substr (pos, new_pos-pos); | |
1713 size_t dot_pos; | |
1714 | |
1715 while ((dot_pos = line.find_first_of ('.')) == std::string::npos) | |
1716 { | |
1717 // Trim trailing blanks on line | |
1718 line = line.substr (0, line.find_last_not_of ("\n\t ") + 1); | |
1719 | |
1720 // Append next line | |
1721 size_t tmp_pos = h.find_first_not_of ("\t ", new_pos + 1); | |
1722 if (tmp_pos == std::string::npos || h.substr (tmp_pos, 1) == "\n") | |
1723 break; | |
1724 | |
1725 new_pos = h.find_first_of ('\n', tmp_pos); | |
1726 std::string next = h.substr (tmp_pos, new_pos-tmp_pos); | |
1727 | |
1728 if (short_sentence) | |
1729 { | |
1730 // Only add the next line if it terminates the sentence, then break | |
1731 if ((tmp_pos = next.find_first_of ('.')) != std::string::npos) | |
1732 { | |
1733 line = line + " " + next; | |
1734 dot_pos = line.find_first_of ('.'); | |
1735 } | |
1736 break; | |
1737 } | |
1738 else | |
1739 line = line + " " + next; | |
1740 } | |
1741 | |
1742 if (dot_pos == std::string::npos) | |
1743 retval = line; | |
1744 else | 953 else |
1745 retval = line.substr (0, dot_pos + 1); | 954 { |
1746 } | 955 dir = file_ops::canonicalize_file_name (dir); |
1747 | 956 |
1748 return retval; | 957 // FIXME -- This seems very inefficient. Is there a better way? |
1749 } | 958 std::list<std::string> list; |
1750 | 959 for (int i = 0; i < ffl_len; i++) |
1751 static void | 960 { |
1752 print_lookfor (const std::string& name, const std::string& line) | 961 const std::string filename = do_which (ffl [i]); |
1753 { | 962 if (file_is_in_dir (filename, dir)) |
1754 const size_t deflen = 20; | 963 list.push_back (ffl [i]); |
1755 | 964 } |
1756 size_t max_width = command_editor::terminal_cols () - deflen; | 965 for (int i = 0; i < afl_len; i++) |
1757 if (max_width < deflen) | 966 { |
1758 max_width = deflen; | 967 const std::string filename = do_which (afl [i]); |
1759 | 968 if (file_is_in_dir (filename, dir)) |
1760 size_t name_len = name.length (); | 969 list.push_back (afl [i]); |
1761 | 970 } |
1762 size_t width = max_width; | 971 |
1763 if (name_len > deflen) | 972 Cell C (list.size (), 1); |
1764 { | 973 int j = 0; |
1765 width = command_editor::terminal_cols () - name_len; | 974 for (std::list<std::string>::const_iterator iter = list.begin (); |
1766 if (width < deflen) | 975 iter != list.end (); iter++) |
1767 width = deflen; | 976 { |
1768 } | 977 C (j++, 0) = octave_value (*iter); |
1769 | 978 } |
1770 size_t pad_len = deflen > name_len ? deflen - name_len + 1 : 1; | 979 |
1771 octave_stdout << name << std::string (pad_len, ' '); | 980 retval.append (octave_value (C)); |
1772 | 981 } |
1773 size_t pos = 0; | 982 } |
1774 | |
1775 while (1) | |
1776 { | |
1777 size_t new_pos = line.find_first_of ("\n\t ", pos); | |
1778 size_t end_pos = new_pos; | |
1779 | |
1780 if (line.length () - pos < width) | |
1781 new_pos = end_pos = std::string::npos; | |
1782 else | |
1783 while (new_pos != std::string::npos && new_pos - pos < width) | |
1784 { | |
1785 end_pos = new_pos; | |
1786 new_pos = line.find_first_of ("\n\t ", new_pos + 1); | |
1787 } | |
1788 | |
1789 octave_stdout << line.substr (pos, end_pos-pos) << std::endl; | |
1790 | |
1791 if (end_pos == std::string::npos) | |
1792 break; | |
1793 | |
1794 pos = end_pos + 1; | |
1795 width = max_width; | |
1796 octave_stdout << std::string (deflen + 1, ' '); | |
1797 } | |
1798 } | |
1799 | |
1800 DEFCMD (lookfor, args, nargout, | |
1801 "-*- texinfo -*-\n\ | |
1802 @deffn {Command} lookfor @var{str}\n\ | |
1803 @deffnx {Command} lookfor -all @var{str}\n\ | |
1804 @deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor (@var{str})\n\ | |
1805 @deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor ('-all', @var{str})\n\ | |
1806 Search for the string @var{str} in all of the functions found in the\n\ | |
1807 function search path. By default @code{lookfor} searches for @var{str}\n\ | |
1808 in the first sentence of the help string of each function found. The entire\n\ | |
1809 help string of each function found in the path can be searched if\n\ | |
1810 the '-all' argument is supplied. All searches are case insensitive.\n\ | |
1811 \n\ | |
1812 Called with no output arguments, @code{lookfor} prints the list of matching\n\ | |
1813 functions to the terminal. Otherwise the output arguments @var{fun} and\n\ | |
1814 @var{helpstring} define the matching functions and the first sentence of\n\ | |
1815 each of their help strings.\n\ | |
1816 \n\ | |
1817 Note that the ability of @code{lookfor} to correctly identify the first\n\ | |
1818 sentence of the help of the functions is dependent on the format of the\n\ | |
1819 functions help. All of the functions in Octave itself will correctly\n\ | |
1820 find the first sentence, but the same cannot be guaranteed for other\n\ | |
1821 functions. Therefore the use of the '-all' argument might be necessary\n\ | |
1822 to find related functions that are not part of Octave.\n\ | |
1823 @seealso{help, which}\n\ | |
1824 @end deffn") | |
1825 { | |
1826 octave_value_list retval; | |
1827 | |
1828 int nargin = args.length (); | |
1829 bool first_sentence_only = true; | |
1830 | |
1831 if (nargin != 1 && nargin != 2) | |
1832 { | |
1833 print_usage (); | |
1834 return retval; | |
1835 } | |
1836 | |
1837 string_vector ret[2]; | |
1838 | |
1839 std::string txt; | |
1840 | |
1841 if (args(0).is_string ()) | |
1842 { | |
1843 txt = args(0).string_value (); | |
1844 | |
1845 if (nargin == 2) | |
1846 { | |
1847 if (args(1).is_string ()) | |
1848 { | |
1849 std::string tmp = args(1).string_value (); | |
1850 | |
1851 if (txt.substr(0,1) == "-") | |
1852 { | |
1853 txt = tmp; | |
1854 tmp = args(0).string_value (); | |
1855 } | |
1856 | |
1857 if (tmp == "-all") | |
1858 first_sentence_only = false; | |
1859 else | |
1860 error ("lookfor: unrecognized option argument"); | |
1861 } | |
1862 else | |
1863 error ("lookfor: arguments must be a string"); | |
1864 } | |
1865 } | |
1866 else | |
1867 error ("lookfor: argument must be a string"); | |
1868 | |
1869 if (!error_state) | |
1870 { | |
1871 // All tests in lower case | |
1872 std::transform (txt.begin (), txt.end (), txt.begin (), tolower); | |
1873 | |
1874 help_list *ptr = keyword_help (); | |
1875 while (ptr->name) | |
1876 { | |
1877 std::string name = ptr->name; | |
1878 std::string h = ptr->help; | |
1879 | |
1880 if (name.find (txt) != std::string::npos) | |
1881 { | |
1882 if (nargout) | |
1883 { | |
1884 ret[0].append (name); | |
1885 ret[1].append (first_help_sentence (h)); | |
1886 } | |
1887 else | |
1888 print_lookfor (name, first_help_sentence (h)); | |
1889 } | |
1890 else | |
1891 { | |
1892 std::string s; | |
1893 | |
1894 if (first_sentence_only) | |
1895 s = first_help_sentence (h); | |
1896 else | |
1897 s = h; | |
1898 | |
1899 std::transform (s.begin (), s.end (), s.begin (), tolower); | |
1900 | |
1901 if (s.length () > 0 && s.find (txt) != std::string::npos) | |
1902 { | |
1903 if (nargout) | |
1904 { | |
1905 ret[0].append (name); | |
1906 ret[1].append (first_help_sentence (h)); | |
1907 } | |
1908 else | |
1909 print_lookfor (name, first_help_sentence (h)); | |
1910 } | |
1911 } | |
1912 | |
1913 OCTAVE_QUIT; | |
1914 | |
1915 ptr++; | |
1916 } | |
1917 | |
1918 ptr = operator_help (); | |
1919 while (ptr->name) | |
1920 { | |
1921 std::string name = ptr->name; | |
1922 std::string h = ptr->help; | |
1923 | |
1924 if (name.find (txt) != std::string::npos) | |
1925 { | |
1926 if (nargout) | |
1927 { | |
1928 ret[0].append (name); | |
1929 ret[1].append (first_help_sentence (h)); | |
1930 } | |
1931 else | |
1932 print_lookfor (name, first_help_sentence (h)); | |
1933 } | |
1934 else | |
1935 { | |
1936 std::string s; | |
1937 if (first_sentence_only) | |
1938 s = first_help_sentence (h); | |
1939 else | |
1940 s = h; | |
1941 | |
1942 std::transform (s.begin (), s.end (), s.begin (), tolower); | |
1943 | |
1944 if (s.length () > 0 && s.find (txt) != std::string::npos) | |
1945 { | |
1946 if (nargout) | |
1947 { | |
1948 ret[0].append (name); | |
1949 ret[1].append (first_help_sentence (h)); | |
1950 } | |
1951 else | |
1952 print_lookfor (name, first_help_sentence (h)); | |
1953 } | |
1954 } | |
1955 | |
1956 OCTAVE_QUIT; | |
1957 | |
1958 ptr++; | |
1959 } | |
1960 | |
1961 string_vector names; | |
1962 | |
1963 #ifdef OLD_SYMTAB | |
1964 // Check the symbol record table | |
1965 names = fbi_sym_tab->name_list (string_vector (), true); | |
1966 | |
1967 for (octave_idx_type i = 0; i < names.length (); i++) | |
1968 { | |
1969 std::string name = names (i); | |
1970 | |
1971 OCTAVE_QUIT; | |
1972 | |
1973 symbol_record *sr = lookup_by_name (name, 0); | |
1974 if (sr && sr->is_defined () | |
1975 && sr->type_name () != "overloaded function") | |
1976 { | |
1977 std::string h = sr->help (); | |
1978 | |
1979 if (name.find (txt) != std::string::npos) | |
1980 { | |
1981 if (nargout) | |
1982 { | |
1983 ret[0].append (name); | |
1984 ret[1].append (first_help_sentence (h)); | |
1985 } | |
1986 else | |
1987 print_lookfor (name, first_help_sentence (h)); | |
1988 } | |
1989 else | |
1990 { | |
1991 std::string s; | |
1992 | |
1993 if (first_sentence_only) | |
1994 s = first_help_sentence (h); | |
1995 else | |
1996 s = h; | |
1997 | |
1998 std::transform (s.begin (), s.end (), s.begin (), tolower); | |
1999 | |
2000 if (s.length () > 0 && s.find (txt) != std::string::npos) | |
2001 { | |
2002 if (nargout) | |
2003 { | |
2004 ret[0].append (name); | |
2005 ret[1].append (first_help_sentence (h)); | |
2006 } | |
2007 else | |
2008 print_lookfor (name, first_help_sentence (h)); | |
2009 } | |
2010 } | |
2011 } | |
2012 } | |
2013 #endif | |
2014 | |
2015 string_vector dirs = load_path::dirs (); | |
2016 | |
2017 int len = dirs.length (); | |
2018 | |
2019 for (int i = 0; i < len; i++) | |
2020 { | |
2021 names = load_path::files (dirs[i]); | |
2022 | |
2023 if (! names.empty ()) | |
2024 { | |
2025 for (int j = 0; j < names.length (); j++) | |
2026 { | |
2027 std::string name = names (j); | |
2028 | |
2029 OCTAVE_QUIT; | |
2030 | |
2031 // Strip extension | |
2032 size_t l = name.length (); | |
2033 if (l > 4 && name.substr (l-4) == ".oct") | |
2034 name = name.substr (0, l - 4); | |
2035 else if (l > 2 && name.substr (l-2) == ".m") | |
2036 name = name.substr (0, l - 2); | |
2037 else | |
2038 continue; | |
2039 | |
2040 #ifdef OLD_SYMTAB | |
2041 // Check if already in symbol table | |
2042 symbol_record *sr = fbi_sym_tab->lookup (name); | |
2043 | |
2044 if (!sr) | |
2045 { | |
2046 // Check if this version is first in the path | |
2047 | |
2048 std::string file_name = load_path::find_fcn (name); | |
2049 | |
2050 std::string dir = dirs[i]; | |
2051 | |
2052 if (! file_ops::is_dir_sep (dir[dir.length()-1])) | |
2053 dir += file_ops::dir_sep_str (); | |
2054 | |
2055 if (file_name == dir + name + ".oct" | |
2056 || file_name == dir + name + ".m") | |
2057 { | |
2058 bool symbol_found; | |
2059 | |
2060 std::string h; | |
2061 if (file_name == dir + name + ".oct") | |
2062 { | |
2063 // oct-file. Must load to get help | |
2064 sr = lookup_by_name (name, false); | |
2065 | |
2066 if (sr && sr->is_defined ()) | |
2067 h = sr->help (); | |
2068 } | |
2069 else | |
2070 h = get_help_from_file (file_name, symbol_found); | |
2071 | |
2072 if (name.find (txt) != std::string::npos) | |
2073 { | |
2074 if (nargout) | |
2075 { | |
2076 ret[0].append (name); | |
2077 ret[1].append (first_help_sentence (h)); | |
2078 } | |
2079 else | |
2080 print_lookfor (name, first_help_sentence (h)); | |
2081 } | |
2082 else | |
2083 { | |
2084 std::string s; | |
2085 if (first_sentence_only) | |
2086 s = first_help_sentence (h); | |
2087 else | |
2088 s = h; | |
2089 | |
2090 std::transform (s.begin (), s.end (), s.begin (), tolower); | |
2091 | |
2092 if (s.length () > 0 && s.find (txt) != std::string::npos) | |
2093 { | |
2094 if (nargout) | |
2095 { | |
2096 ret[0].append (name); | |
2097 ret[1].append (first_help_sentence (h)); | |
2098 } | |
2099 else | |
2100 print_lookfor (name, first_help_sentence (h)); | |
2101 } | |
2102 } | |
2103 } | |
2104 } | |
2105 #endif | |
2106 | |
2107 // Check if this function has autoloaded functions attached to it | |
2108 std::string file_name = load_path::find_fcn (name); | |
2109 | |
2110 string_vector autoload_fcns = reverse_lookup_autoload (file_name); | |
2111 | |
2112 if (! autoload_fcns.empty ()) | |
2113 { | |
2114 for (int k = 0; k < autoload_fcns.length (); k++) | |
2115 { | |
2116 std::string aname = autoload_fcns (k); | |
2117 | |
2118 #ifdef OLD_SYMTAB | |
2119 // Check if already in symbol table | |
2120 sr = fbi_sym_tab->lookup (aname); | |
2121 | |
2122 if (!sr) | |
2123 { | |
2124 // Must load to get help | |
2125 sr = lookup_by_name (aname, false); | |
2126 | |
2127 std::string h; | |
2128 if (sr && sr->is_defined ()) | |
2129 h = sr->help (); | |
2130 | |
2131 if (aname.find (txt) != std::string::npos) | |
2132 { | |
2133 if (nargout) | |
2134 { | |
2135 ret[0].append (aname); | |
2136 ret[1].append (first_help_sentence (h)); | |
2137 } | |
2138 else | |
2139 print_lookfor (aname, first_help_sentence (h)); | |
2140 } | |
2141 else | |
2142 { | |
2143 std::string s; | |
2144 if (first_sentence_only) | |
2145 s = first_help_sentence (h); | |
2146 else | |
2147 s = h; | |
2148 | |
2149 std::transform (s.begin (), s.end (), s.begin (), | |
2150 tolower); | |
2151 | |
2152 if (s.length () > 0 && s.find (txt) != std::string::npos) | |
2153 { | |
2154 if (nargout) | |
2155 { | |
2156 ret[0].append (aname); | |
2157 ret[1].append (first_help_sentence (h)); | |
2158 } | |
2159 else | |
2160 print_lookfor (aname, first_help_sentence (h)); | |
2161 } | |
2162 } | |
2163 } | |
2164 #endif | |
2165 } | |
2166 } | |
2167 } | |
2168 } | |
2169 } | |
2170 | |
2171 if (nargout != 0) | |
2172 { | |
2173 retval (1) = ret[1]; | |
2174 retval (0) = ret[0]; | |
2175 } | |
2176 } | |
2177 else | |
2178 { | |
2179 error ("lookfor: argument must be a string"); | |
2180 } | |
2181 | 983 |
2182 return retval; | 984 return retval; |
2183 } | 985 } |
2184 | 986 |
2185 DEFUN (info_file, args, nargout, | 987 DEFUN (info_file, args, nargout, |