7325
|
1 ## Copyright (C) 2001, 2007 Paul Kienzle |
|
2 ## |
|
3 ## This file is part of Octave. |
|
4 ## |
|
5 ## Octave is free software; you can redistribute it and/or modify it |
|
6 ## under the terms of the GNU General Public License as published by |
|
7 ## the Free Software Foundation; either version 3 of the License, or (at |
|
8 ## your option) any later version. |
|
9 ## |
|
10 ## Octave is distributed in the hope that it will be useful, but |
|
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 ## General Public License for more details. |
|
14 ## |
|
15 ## You should have received a copy of the GNU General Public License |
|
16 ## along with Octave; see the file COPYING. If not, see |
|
17 ## <http://www.gnu.org/licenses/>. |
|
18 |
|
19 ## -*- texinfo -*- |
|
20 ## @deftypefn {Command} edit @var{name} |
|
21 ## @deftypefnx {Command} edit @var{field} @var{value} |
|
22 ## @deftypefnx {Command} @var{value} = edit get @var{field} |
|
23 ## Edit the named function, or change editor settings. |
|
24 ## |
|
25 ## If @code{edit} is called with the name of a file or function as |
|
26 ## its argument it will be opened in a text editor. |
|
27 ## |
|
28 ## @itemize @bullet |
|
29 ## @item |
|
30 ## If the function @var{name} is available in a file on your path and |
|
31 ## that file is modifiable, then it will be edited in place. If it |
|
32 ## is a system function, then it will first be copied to the directory |
|
33 ## @code{HOME} (see further down) and then edited. |
|
34 ## |
|
35 ## @item |
|
36 ## If @var{name} is the name of a function defined in the interpreter but |
|
37 ## not in an m-file, then an m-file will be created in @code{HOME} |
|
38 ## to contain that function along with its current definition. |
|
39 ## |
|
40 ## @item |
|
41 ## If @code{name.cc} is specified, then it will search for @code{name.cc} |
|
42 ## in the path and try to modify it, otherwise it will create a new |
|
43 ## @file{.cc} file in @code{HOME}. If @var{name} happens to be an |
|
44 ## m-file or interpreter defined function, then the text of that |
|
45 ## function will be inserted into the .cc file as a comment. |
|
46 ## |
|
47 ## @item |
|
48 ## If @var{name.ext} is on your path then it will be editted, otherwise |
|
49 ## the editor will be started with @file{HOME/name.ext} as the |
|
50 ## filename. If @file{name.ext} is not modifiable, it will be copied to |
|
51 ## @code{HOME} before editing. |
|
52 ## |
|
53 ## @strong{WARNING!} You may need to clear name before the new definition |
|
54 ## is available. If you are editing a .cc file, you will need |
|
55 ## to mkoctfile @file{name.cc} before the definition will be available. |
|
56 ## @end itemize |
|
57 ## |
|
58 ## If @code{edit} is called with @var{field} and @var{value} variables, |
|
59 ## the value of the control field @var{field} will be @var{value}. |
|
60 ## If an output argument is requested and the first argument is @code{get} |
|
61 ## then @code{edit} will return the value of the control field @var{field}. |
|
62 ## The following control fields are used: |
|
63 ## |
|
64 ## @table @samp |
|
65 ## @item editor |
|
66 ## This is the editor to use to modify the functions. By default it uses |
|
67 ## Octave's @code{EDITOR} built-in function, which comes from |
|
68 ## @code{getenv("EDITOR")} and defaults to @code{emacs}. Use @code{%s} |
|
69 ## In place of the function name. For example, |
|
70 ## @table @samp |
|
71 ## @item [EDITOR, " %s"] |
|
72 ## Use the editor which Octave uses for @code{bug_report}. |
|
73 ## @item "xedit %s &" |
|
74 ## pop up simple X11 editor in a separate window |
|
75 ## @item "gnudoit -q \"(find-file \\\"%s\\\")\"" |
|
76 ## Send it to current Emacs; must have @code{(gnuserv-start)} in @file{.emacs}. |
|
77 ## @end table |
|
78 ## |
|
79 ## On cygwin, you will need to convert the cygwin path to a windows |
|
80 ## path if you are using a native Windows editor. For example |
|
81 ## @example |
|
82 ## '"C:/Program Files/Good Editor/Editor.exe" "$(cygpath -wa %s)"' |
|
83 ## @end example |
|
84 ## |
|
85 ## @item home |
|
86 ## This is the location of user local m-files. Be be sure it is in your |
|
87 ## path. The default is @file{~/octave}. |
|
88 ## |
|
89 ## @item author |
|
90 ## This is the name to put after the "## Author:" field of new functions. |
|
91 ## By default it guesses from the @code{gecos} field of password database. |
|
92 ## |
|
93 ## @item email |
|
94 ## This is the e-mail address to list after the name in the author field. |
|
95 ## By default it guesses @code{<$LOGNAME@@$HOSTNAME>}, and if @code{$HOSTNAME} |
|
96 ## is not defined it uses @code{uname -n}. You probably want to override this. |
|
97 ## Be sure to use @code{<user@@host>} as your format. |
|
98 ## |
|
99 ## @item license |
|
100 ## @table @samp |
|
101 ## @item gpl |
|
102 ## GNU General Public License (default). |
|
103 ## @item bsd |
|
104 ## BSD-style license without advertising clause. |
|
105 ## @item pd |
|
106 ## Public domain. |
|
107 ## @item "text" |
|
108 ## Your own default copyright and license. |
|
109 ## @end table |
|
110 ## |
|
111 ## @item mode |
|
112 ## This value determines whether the editor should be started in async mode |
|
113 ## or sync mode. Set it to "async" to start the editor in async mode. The |
|
114 ## default is "sync" (see also "system"). |
|
115 ## |
|
116 ## Unless you specify @samp{pd}, edit will prepend the copyright statement |
|
117 ## with "Copyright (C) yyyy Function Author". |
|
118 ## @end table |
|
119 ## @end deftypefn |
|
120 |
|
121 ## Author: Paul Kienzle <pkienzle@users.sf.net> |
|
122 |
|
123 ## Original version by Paul Kienzle distributed as free software in the |
|
124 ## public domain. |
|
125 |
|
126 ## PKG_ADD: mark_as_command edit |
|
127 |
|
128 function ret = edit (file, state) |
|
129 |
|
130 ## Pick up globals or default them. |
|
131 |
|
132 persistent FUNCTION = struct ("EDITOR", strcat (EDITOR (), " %s"), |
|
133 "HOME", fullfile (default_home, "octave"), |
|
134 "AUTHOR", default_user(1), |
|
135 "EMAIL", [], |
|
136 "LICENSE", "GPL", |
|
137 "MODE", "sync"); |
|
138 |
|
139 mlock; # make sure the state variables survive "clear functions" |
|
140 |
|
141 if (nargin == 2) |
|
142 switch (toupper (file)) |
|
143 case "EDITOR" |
|
144 FUNCTION.EDITOR = state; |
|
145 case "HOME" |
|
146 if (! isempty (state) && state(1) == "~") |
|
147 state = [ default_home, state(2:end) ]; |
|
148 endif |
|
149 FUNCTION.HOME = state; |
|
150 case "AUTHOR" |
|
151 FUNCTION.AUTHOR = state; |
|
152 case "EMAIL" |
|
153 FUNCTION.EMAIL = state; |
|
154 case "LICENSE" |
|
155 FUNCTION.LICENSE = state; |
|
156 case "MODE" |
|
157 if (strcmp (state, "sync") || strcmp (state, "async")) |
|
158 FUNCTION.MODE = state; |
|
159 else |
|
160 error('expected "edit MODE sync|async"'); |
|
161 endif |
|
162 case "GET" |
|
163 ret = FUNCTION.(toupper (state)); |
|
164 otherwise |
|
165 error ("expected \"edit EDITOR|HOME|AUTHOR|EMAIL|LICENSE|MODE val\""); |
|
166 endswitch |
|
167 return |
|
168 endif |
|
169 |
|
170 ## Start the editor without a file if no file is given. |
|
171 if (nargin < 1) |
|
172 if (exist (FUNCTION.HOME, "dir") == 7 && (isunix () || ! ispc ())) |
|
173 system (strcat ("cd \"", FUNCTION.HOME, "\" ; ", |
|
174 sprintf (FUNCTION.EDITOR, "")), |
|
175 [], FUNCTION.MODE); |
|
176 else |
|
177 system (sprintf (FUNCTION.EDITOR,""), [], FUNCTION.MODE); |
|
178 endif |
|
179 return; |
|
180 endif |
|
181 |
|
182 ## Check whether the user is trying to edit a builtin of compiled function. |
|
183 switch (exist (file)) |
|
184 case {3, 5} |
|
185 error ("unable to edit a built-in or compiled function"); |
|
186 endswitch |
|
187 |
|
188 ## Find file in path. |
|
189 idx = rindex (file, "."); |
|
190 if (idx != 0) |
|
191 ## If file has an extension, use it. |
|
192 path = file_in_loadpath (file); |
|
193 else |
|
194 ## Otherwise try file.cc, and if that fails, default to file.m. |
|
195 path = file_in_loadpath (fullfile (file, ".cc")); |
|
196 if (isempty (path)) |
|
197 file = fullfile (file, ".m"); |
|
198 path = file_in_loadpath (file); |
|
199 endif |
|
200 endif |
|
201 |
|
202 ## If the file exists and is modifiable in place then edit it, |
|
203 ## otherwise copy it and then edit it. |
|
204 if (! isempty (path)) |
|
205 fid = fopen (path, "r+t"); |
|
206 if (fid < 0) |
|
207 from = path; |
|
208 path = strcat (FUNCTION.HOME, from (rindex (from, filesep):end)) |
|
209 [status, msg] = copyfile (from, path, 1); |
|
210 if (status == 0) |
|
211 error (msg); |
|
212 endif |
|
213 else |
|
214 fclose(fid); |
|
215 endif |
|
216 system (sprintf (FUNCTION.EDITOR, strcat ("\"", path, "\"")), |
|
217 [], FUNCTION.MODE); |
|
218 return; |
|
219 endif |
|
220 |
|
221 ## If editing something other than a m-file or an oct-file, just |
|
222 ## edit it. |
|
223 idx = rindex (file, filesep); |
|
224 if (idx != 0) |
|
225 path = file; |
|
226 else |
|
227 path = fullfile (FUNCTION.HOME, file); |
|
228 endif |
|
229 idx = rindex (file, "."); |
|
230 name = file(1:idx-1); |
|
231 ext = file(idx+1:end); |
|
232 switch (ext) |
|
233 case { "cc", "m" } |
|
234 0; |
|
235 otherwise |
|
236 system (sprintf (FUNCTION.EDITOR, strcat ("\"", path, "\"")), |
|
237 [], FUNCTION.MODE); |
|
238 return; |
|
239 endswitch |
|
240 |
|
241 ## The file doesn't exist in path so create it, put in the function |
|
242 ## template and edit it. |
|
243 |
|
244 ## Guess the email name if it was not given. |
|
245 if (isempty (FUNCTION.EMAIL)) |
|
246 host = getenv("HOSTNAME"); |
|
247 if (isempty (host) && ispc ()) |
|
248 host = getenv ("COMPUTERNAME"); |
|
249 endif |
|
250 if (isempty (host)) |
|
251 [status, host] = system ("uname -n"); |
|
252 ## trim newline from end of hostname |
|
253 if (! isempty (host)) |
|
254 host = host(1:end-1); |
|
255 endif |
|
256 endif |
|
257 if (isempty (host)) |
|
258 FUNCTION.EMAIL = " "; |
|
259 else |
|
260 FUNCTION.EMAIL = strcat ("<", default_user(0), "@", host, ">"); |
|
261 endif |
|
262 endif |
|
263 |
|
264 ## Fill in the revision string. |
|
265 now = localtime (time); |
|
266 revs = strcat (strftime ("%Y-%m-%d", now), " ", FUNCTION.AUTHOR, " ", |
|
267 FUNCTION.EMAIL, "\n* Initial revision"); |
|
268 |
|
269 ## Fill in the copyright string. |
|
270 copyright = strcat (strftime ("Copyright (C) %Y ", now), FUNCTION.AUTHOR); |
|
271 |
|
272 ## Fill in the author tag field. |
|
273 author = strcat ("Author: ", FUNCTION.AUTHOR, " ", FUNCTION.EMAIL); |
|
274 |
|
275 ## Fill in the header. |
|
276 uclicense = toupper (FUNCTION.LICENSE); |
|
277 switch (uclicense) |
|
278 case "GPL" |
|
279 head = strcat (copyright, "\n\n", "\ |
|
280 This program is free software; you can redistribute it and/or modify\n\ |
|
281 it under the terms of the GNU General Public License as published by\n\ |
|
282 the Free Software Foundation; either version 2 of the License, or\n\ |
|
283 (at your option) any later version.\n\ |
|
284 \n\ |
|
285 This program is distributed in the hope that it will be useful,\n\ |
|
286 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ |
|
287 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ |
|
288 GNU General Public License for more details.\n\ |
|
289 \n\ |
|
290 You should have received a copy of the GNU General Public License\n\ |
|
291 along with this program; if not, write to the Free Software\n\ |
|
292 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\ |
|
293 "); |
|
294 tail = strcat (author, "\n\n", revs); |
|
295 |
|
296 case "BSD" |
|
297 head = strcat (copyright, "\n\n", "\ |
|
298 This program is free software; redistribution and use in source and\n\ |
|
299 binary forms, with or without modification, are permitted provided that\n\ |
|
300 the following conditions are met:\n\ |
|
301 \n\ |
|
302 1.Redistributions of source code must retain the above copyright\n\ |
|
303 notice, this list of conditions and the following disclaimer.\n\ |
|
304 2.Redistributions in binary form must reproduce the above copyright\n\ |
|
305 notice, this list of conditions and the following disclaimer in the\n\ |
|
306 documentation and/or other materials provided with the distribution.\n\ |
|
307 \n\ |
|
308 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n\ |
|
309 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\ |
|
310 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n\ |
|
311 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n\ |
|
312 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\ |
|
313 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n\ |
|
314 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n\ |
|
315 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n\ |
|
316 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n\ |
|
317 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n\ |
|
318 SUCH DAMAGE.\ |
|
319 "); |
|
320 tail = strcat (author, "\n\n", revs); |
|
321 |
|
322 case "PD" |
|
323 head = ""; |
|
324 tail = strcat (author, "\n\n", |
|
325 "This program is granted to the public domain\n\n", |
|
326 revs); |
|
327 |
|
328 otherwise |
|
329 head = ""; |
|
330 tail = strcat (copyright, "\n\n", FUNCTION.LICENSE, "\n", |
|
331 author, "\n\n", revs); |
|
332 endswitch |
|
333 |
|
334 ## Generate the function template. |
|
335 exists = exist (name); |
|
336 switch (ext) |
|
337 case {"cc", "C", "cpp"} |
|
338 if (isempty (head)) |
|
339 comment = strcat ("/*\n", tail, "\n\n*/\n\n"); |
|
340 else |
|
341 comment = strcat ("/*\n", head, "\n\n", tail, "\n\n*/\n\n"); |
|
342 endif |
|
343 ## If we are shadowing an m-file, paste the code for the m-file. |
|
344 if (any (exists == [2, 103])) |
|
345 code = strcat ("\\ ", strrep (type (name), "\n", "\n// ")); |
|
346 else |
|
347 code = " "; |
|
348 endif |
|
349 body = strcat ("#include <octave/oct.h>\n\n", |
|
350 "DEFUN_DLD(", name, ",args,nargout,\"\\\n", |
|
351 name, "\\n\\\n\")\n{\n", |
|
352 " octave_value_list retval;\n", |
|
353 " int nargin = args.length();\n\n", |
|
354 code, "\n return retval;\n}\n"); |
|
355 |
|
356 text = strcat (comment, body); |
|
357 case "m" |
|
358 ## If we are editing a function defined on the fly, paste the |
|
359 ## code. |
|
360 if (any (exists == [2, 103])) |
|
361 body = type (name); |
|
362 else |
|
363 body = strcat ("function [ ret ] = ", name, " ()\n\nendfunction\n"); |
|
364 endif |
|
365 if (isempty (head)) |
|
366 comment = strcat ("## ", name, "\n\n", |
|
367 "## ", strrep (tail, "\n", "\n## "), "\n\n"); |
|
368 else |
|
369 comment = strcat ("## ", strrep(head,"\n","\n## "), "\n\n", ... |
|
370 "## ", name, "\n\n", ... |
|
371 "## ", strrep (tail, "\n", "\n## "), "\n\n"); |
|
372 endif |
|
373 text = strcat (comment, body); |
|
374 endswitch |
|
375 |
|
376 ## Write the initial file (if there is anything to write) |
|
377 fid = fopen (path, "wt"); |
|
378 if (fid < 0) |
|
379 error ("edit: could not create %s", path); |
|
380 endif |
|
381 fputs (fid, text); |
|
382 fclose (fid); |
|
383 |
|
384 ## Finally we are ready to edit it! |
|
385 system (sprintf (FUNCTION.EDITOR, strcat ("\"", path, "\"")), |
|
386 [], FUNCTION.MODE); |
|
387 |
|
388 endfunction |
|
389 |
|
390 function ret = default_home () |
|
391 |
|
392 ret = getenv ("HOME"); |
|
393 if (isempty (ret)) |
|
394 ret = glob ("~"); |
|
395 if (! isempty (ret)) |
|
396 ret = ret{1}; |
|
397 else |
|
398 ret = ""; |
|
399 endif |
|
400 endif |
|
401 |
|
402 endfunction |
|
403 |
|
404 ## default_user (form) |
|
405 ## Returns the name associated with the current user ID. |
|
406 ## |
|
407 ## If form==1 return the full name. This will be the |
|
408 ## default author. If form==0 return the login name. |
|
409 ## login@host will be the default email address. |
|
410 |
|
411 function ret = default_user (long_form) |
|
412 |
|
413 ent = getpwuid (getuid); |
|
414 if (! isstruct (ent)) |
|
415 ret = getenv ("USER"); |
|
416 if (isempty ()) |
|
417 ret = getenv ("USERNAME"); |
|
418 endif |
|
419 elseif (long_form) |
|
420 ret = ent.gecos; |
|
421 else |
|
422 ret = ent.name; |
|
423 endif |
|
424 |
|
425 endfunction |