/* $LynxId: LYEdit.c,v 1.42 2013/11/28 11:18:19 tom Exp $ */ #include #include #include #include #include #include #include #include #ifdef VMS #include #endif /* VMS */ #include #include BOOLEAN editor_can_position(void) { char *value; HTList *p = positionable_editor; static const char *table[] = { #ifdef VMS "sedt", #else "emacs", /* + xemacs */ "jed", "jmacs", "joe", /* + rjoe */ "jove", "jstar", "nano", "pico", /* + jpico */ "vi" /* + vim, xvi, vile, elvis, view... + likely false matches */ #endif }; unsigned n; for (n = 0; n < TABLESIZE(table); n++) { if (LYstrstr(editor, table[n]) != 0) { return TRUE; } } /* * This really isn't right. LYstrstr() might be too lax, * but this should at least match basename to basename... */ if (positionable_editor != NULL) { while ((value = (char *) HTList_nextObject(p)) != NULL) { if (strcmp(editor, value) == 0) { return TRUE; } } } return FALSE; } /* * In edit mode invoke the given (or default) editor to display and edit the * current file. For editors listed in 'editor_can_position()', Lynx will open * the file to the same line that the screen cursor is on (or close...) when * editing is invoked. * * Returns FALSE if file is uneditable. */ int edit_current_file(char *newfile, int cur, int lineno) { int result = FALSE; char *filename = NULL; #if !(defined(VMS) || defined(USE_DOS_DRIVES)) char *colon; #endif char *number_sign; char position[80]; #if defined(VMS) || defined(CANT_EDIT_UNWRITABLE_FILES) FILE *fp; #endif CTRACE((tfp, "edit_current_file(newfile=%s, cur=%d, lineno=%d)\n", newfile, cur, lineno)); /* * If it's a remote file then we can't edit it. */ if (!LYisLocalFile(newfile)) { HTUserMsg(CANNOT_EDIT_REMOTE_FILES); return FALSE; } /* * If there's a fragment, trim it. - FM */ number_sign = trimPoundSelector(newfile); /* * On Unix, first try to open it as a completely referenced file, then via * the path alone. * * On VMS, only try the path. */ #if defined (VMS) || defined (USE_DOS_DRIVES) filename = HTParse(newfile, "", PARSE_PATH + PARSE_PUNCTUATION); HTUnEscape(filename); StrAllocCopy(filename, HTSYS_name(filename)); if (!LYCanReadFile(filename)) { #ifdef SH_EX HTUserMsg2(COULD_NOT_EDIT_FILE, filename); #else HTAlert(COULD_NOT_ACCESS_FILE); #endif CTRACE((tfp, "filename: '%s'\n", filename)); goto done; } #else /* something like UNIX */ if (StrNCmp(newfile, "file://localhost/", 16) == 0) colon = newfile + 16; else colon = StrChr(newfile, ':'); StrAllocCopy(filename, (colon + 1)); HTUnEscape(filename); if (!LYCanReadFile(filename)) { FREE(filename); filename = HTParse(newfile, "", PARSE_PATH + PARSE_PUNCTUATION); HTUnEscape(filename); if (!LYCanReadFile(HTSYS_name(filename))) { HTAlert(COULD_NOT_ACCESS_FILE); goto done; } } #endif #if defined(VMS) || defined(CANT_EDIT_UNWRITABLE_FILES) /* * Don't allow editing if user lacks append access. */ if ((fp = fopen(filename, TXT_A)) == NULL) { HTUserMsg(NOAUTH_TO_EDIT_FILE); goto done; } fclose(fp); #endif /* VMS || CANT_EDIT_UNWRITABLE_FILES */ /* * Make sure cur is at least zero. - FM */ if (cur < 0) { cur = 0; } /* * Set up the command for the editor. - FM */ if (lineno >= 0) { *position = 0; #ifdef VMS lineno--; #endif lineno += (nlinks ? links[cur].ly : 0); if (lineno > 0) sprintf(position, "%d", lineno); } else { *position = '\0'; } edit_temporary_file(filename, position, NULL); result = TRUE; done: /* * Restore the fragment if there was one. - FM */ restorePoundSelector(number_sign); FREE(filename); CTRACE((tfp, "edit_current_file returns %d\n", result)); return (result); } void edit_temporary_file(char *filename, const char *position, const char *message) { #ifdef UNIX struct stat stat_info; #endif const char *format = "%s %s"; char *command = NULL; const char *editor_arg = ""; int params = 1; int rv; if (LYstrstr(editor, "pico")) { editor_arg = " -t"; /* No prompt for filename to use */ } if (editor_can_position() && *position) { #ifdef VMS format = "%s %s -%s%s"; HTAddXpand(&command, format, params++, editor); HTAddParam(&command, format, params++, filename); HTAddParam(&command, format, params++, position); HTAddParam(&command, format, params++, editor_arg); HTEndParam(&command, format, params); #else format = "%s +%s%s %s"; HTAddXpand(&command, format, params++, editor); HTAddParam(&command, format, params++, position); HTAddParam(&command, format, params++, editor_arg); HTAddParam(&command, format, params++, filename); HTEndParam(&command, format, params); #endif } #ifdef DOSPATH else if (StrNCmp(editor, "VZ", 2) == 0) { /* for Vz editor */ format = "%s %s -%s"; HTAddXpand(&command, format, params++, editor); HTAddParam(&command, format, params++, HTDOS_short_name(filename)); HTAddParam(&command, format, params++, position); HTEndParam(&command, format, params); } else if (StrNCmp(editor, "edit", 4) == 0) { /* for standard editor */ HTAddXpand(&command, format, params++, editor); HTAddParam(&command, format, params++, HTDOS_short_name(filename)); HTEndParam(&command, format, params); } #endif else { #ifdef _WINDOWS if (StrChr(editor, ' ')) HTAddXpand(&command, format, params++, HTDOS_short_name(editor)); else HTAddXpand(&command, format, params++, editor); #else HTAddXpand(&command, format, params++, editor); #endif HTAddParam(&command, format, params++, filename); HTEndParam(&command, format, params); } if (message != NULL) { _statusline(message); } CTRACE((tfp, "LYEdit: %s\n", command)); CTRACE_SLEEP(MessageSecs); stop_curses(); #ifdef UNIX set_errno(0); #endif if ((rv = LYSystem(command)) != 0) { /* Spawn Editor */ start_curses(); /* * If something went wrong, we should probably return soon; currently * we don't, but at least put out a message. - kw */ { #if defined(UNIX) && defined(WIFEXITED) int save_err = errno; CTRACE((tfp, "ExtEditForm: system() returned %d (0x%x), %s\n", rv, rv, (save_err ? LYStrerror(save_err) : "reason unknown"))); LYFixCursesOn("show error warning:"); if (rv == -1) { HTUserMsg2(gettext("Error starting editor, %s"), LYStrerror(save_err)); } else if (WIFSIGNALED(rv)) { HTAlwaysAlert(NULL, gettext("Editor killed by signal")); } else if (WIFEXITED(rv) && WEXITSTATUS(rv) != 127) { char exitcode[80]; sprintf(exitcode, "%d", WEXITSTATUS(rv)); HTUserMsg2(gettext("Editor returned with error status %s"), exitcode); } else #endif HTAlwaysAlert(NULL, ERROR_SPAWNING_EDITOR); } } else { start_curses(); } #ifdef UNIX /* * Delete backup file, if that's your style. */ HTSprintf0(&command, "%s~", filename); if (stat(command, &stat_info) == 0) remove(command); #endif FREE(command); }