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,