📄 file.c
字号:
wrapToggle = XtVaCreateManagedWidget("addWrap", xmToggleButtonWidgetClass, formatForm, XmNlabelString, s1=XmStringCreateSimple("Add line breaks where wrapped"), XmNalignment, XmALIGNMENT_BEGINNING, XmNmnemonic, 'A', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, formatBtns, XmNleftAttachment, XmATTACH_FORM, NULL); XtAddCallback(wrapToggle, XmNvalueChangedCallback, addWrapCB, addWrap); XmStringFree(s1); } *addWrap = False; XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_LABEL), XmNmnemonic, 'l', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_TEXT), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_DIR_LIST_LABEL), XmNmnemonic, 'D', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_DIR_LIST), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_LIST_LABEL), XmNmnemonic, 'F', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_LIST), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_SELECTION_LABEL), XmNmnemonic, prompt[strspn(prompt, "lFD")], XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_TEXT), NULL); AddDialogMnemonicHandler(fileSB, FALSE); RemapDeleteKey(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_TEXT)); RemapDeleteKey(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_TEXT)); retVal = HandleCustomNewFileSB(fileSB, fullname, window->filenameSet ? window->filename : NULL); if (retVal != GFN_OK) SetFileDialogDefaultDirectory(savedDefaultDir); if (savedDefaultDir != NULL) XtFree(savedDefaultDir); return retVal;}/*** Find a name for an untitled file, unique in the name space of in the opened** files in this session, i.e. Untitled or Untitled_nn, and write it into** the string "name".*/void UniqueUntitledName(char *name){ WindowInfo *w; int i; for (i=0; i<INT_MAX; i++) { if (i == 0) sprintf(name, "Untitled"); else sprintf(name, "Untitled_%d", i); for (w=WindowList; w!=NULL; w=w->next) if (!strcmp(w->filename, name)) break; if (w == NULL) break; }}/*** Check if the file in the window was changed by an external source.** and put up a warning dialog if it has.*/void CheckForChangesToFile(WindowInfo *window){ static WindowInfo *lastCheckWindow; static Time lastCheckTime = 0; char fullname[MAXPATHLEN]; struct stat statbuf; Time timestamp; FILE *fp; int resp, silent = 0; XWindowAttributes winAttr; if(!window->filenameSet) return; /* If last check was very recent, don't impact performance */ timestamp = XtLastTimestampProcessed(XtDisplay(window->shell)); if (window == lastCheckWindow && timestamp - lastCheckTime < MOD_CHECK_INTERVAL) return; lastCheckWindow = window; lastCheckTime = timestamp; /* Update the status, but don't pop up a dialog if we're called from a place where the window might be iconic (e.g., from the replace dialog) or on another desktop. This works, but I bet it costs a round-trip to the server. Might be better to capture MapNotify/Unmap events instead. */ XGetWindowAttributes(XtDisplay(window->shell), XtWindow(window->shell), &winAttr); if (winAttr.map_state != IsViewable) silent = 1; /* Get the file mode and modification time */ strcpy(fullname, window->path); strcat(fullname, window->filename); if (stat(fullname, &statbuf) != 0) { /* Return if we've already warned the user or we can't warn him now */ if (window->fileMissing || silent) return; /* Can't stat the file -- maybe it's been deleted. The filename is now invalid */ window->fileMissing = TRUE; window->lastModTime = 1; /* Warn the user, if they like to be warned (Maybe this should be its own preference setting: GetPrefWarnFileDeleted() ) */ if (GetPrefWarnFileMods()) { /* See note below about pop-up timing and XUngrabPointer */ XUngrabPointer(XtDisplay(window->shell), timestamp); if( errno == EACCES ) resp = 1 + DialogF(DF_ERR, window->shell, 2, "File not Accessible", "You no longer have access to file \"%s\".\n" "Another program may have changed the permissions one of\n" "its parent directories.\nSave as a new file?", "Save As...", "Dismiss", window->filename); else resp = DialogF(DF_ERR, window->shell, 3, "File not found", "Error while checking the status of file \"%s\":\n" " \"%s\"\n" "Another program may have deleted or moved it.\n" "Re-Save file or Save as a new file?", "Re-Save", "Save As...", "Dismiss", window->filename, errorString()); if (resp == 1) SaveWindow(window); else if (resp == 2) SaveWindowAs(window, NULL, 0); } /* A missing or (re-)saved file can't be read-only. */ SET_PERM_LOCKED(window->lockReasons, False); UpdateWindowTitle(window); UpdateWindowReadOnly(window); return; } /* Check that the file's read-only status is still correct (but only if the file can still be opened successfully in read mode) */ if (window->fileMode != statbuf.st_mode) { window->fileMode = statbuf.st_mode; if ((fp = fopen(fullname, "r")) != NULL) { int readOnly; fclose(fp);#ifndef DONT_USE_ACCESS readOnly = access(fullname, W_OK) != 0;#else if (((fp = fopen(fullname, "r+")) != NULL)) { readOnly = FALSE; fclose(fp); } else readOnly = TRUE;#endif if (IS_PERM_LOCKED(window->lockReasons) != readOnly) { SET_PERM_LOCKED(window->lockReasons, readOnly); UpdateWindowTitle(window); UpdateWindowReadOnly(window); } } } /* Warn the user if the file has been modified, unless checking is turned off or the user has already been warned. Popping up a dialog from a focus callback (which is how this routine is usually called) seems to catch Motif off guard, and if the timing is just right, the dialog can be left with a still active pointer grab from a Motif menu which is still in the process of popping down. The workaround, below, of calling XUngrabPointer is inelegant but seems to fix the problem. */ if (!silent && ((window->lastModTime != 0 && window->lastModTime != statbuf.st_mtime) || window->fileMissing) ){ window->lastModTime = 0; /* Inhibit further warnings */ window->fileMissing = FALSE; if (!GetPrefWarnFileMods()) return; if (GetPrefWarnRealFileMods() && !cmpWinAgainstFile(window, fullname)) { /* Contents hasn't changed. Update the modification time. */ window->lastModTime = statbuf.st_mtime; return; } XUngrabPointer(XtDisplay(window->shell), timestamp); if (window->fileChanged) resp = DialogF(DF_WARN, window->shell, 2, "File modified externally", "%s has been modified by another program. Reload?\n\n" "WARNING: Reloading will discard changes made in this\n" "editing session!", "Reload", "Dismiss", window->filename); else resp = DialogF(DF_WARN, window->shell, 2, "File modified externally", "%s has been modified by another\nprogram. Reload?", "Reload", "Dismiss", window->filename); if (resp == 1) RevertToSaved(window); }}/*** Return true if the file displayed in window has been modified externally** to nedit. This should return FALSE if the file has been deleted or is** unavailable.*/static int fileWasModifiedExternally(WindowInfo *window){ char fullname[MAXPATHLEN]; struct stat statbuf; if(!window->filenameSet) return FALSE; /* if (window->lastModTime == 0) return FALSE; */ strcpy(fullname, window->path); strcat(fullname, window->filename); if (stat(fullname, &statbuf) != 0) return FALSE; if (window->lastModTime == statbuf.st_mtime) return FALSE; if (GetPrefWarnRealFileMods() && !cmpWinAgainstFile(window, fullname)) { return FALSE; } return TRUE;}/*** Check the read-only or locked status of the window and beep and return** false if the window should not be written in.*/int CheckReadOnly(WindowInfo *window){ if (IS_ANY_LOCKED(window->lockReasons)) { XBell(TheDisplay, 0); return True; } return False;}/*** Wrapper for strerror so all the calls don't have to be ifdef'd for VMS.*/static const char *errorString(void){#ifdef VMS return strerror(errno, vaxc$errno);#else return strerror(errno);#endif}#ifdef VMS/*** Removing the VMS version number from a file name (if has one).*/void removeVersionNumber(char *fileName){ char *versionStart; versionStart = strrchr(fileName, ';'); if (versionStart != NULL) *versionStart = '\0';}#endif /*VMS*//*** Callback procedure for File Format toggle buttons. Format is stored** in userData field of widget button*/static void setFormatCB(Widget w, XtPointer clientData, XtPointer callData){ if (XmToggleButtonGetState(w)) XtVaGetValues(w, XmNuserData, clientData, NULL);}/*** Callback procedure for toggle button requesting newlines to be inserted** to emulate continuous wrapping.*/static void addWrapCB(Widget w, XtPointer clientData, XtPointer callData){ int resp; int *addWrap = (int *)clientData; if (XmToggleButtonGetState(w)) { resp = DialogF(DF_WARN, w, 2, "Add Wrap", "This operation adds permanent line breaks to\n" "match the automatic wrapping done by the\n" "Continuous Wrap mode Preferences Option.\n\n" "*** This Option is Irreversable ***\n\n" "Once newlines are inserted, continuous wrapping\n" "will no longer work automatically on these lines", "OK", "Cancel"); if (resp == 2) { XmToggleButtonSetState(w, False, False); *addWrap = False; } else { *addWrap = True; } } else { *addWrap = False; }}/*** Change a window created in NEdit's continuous wrap mode to the more** conventional Unix format of embedded newlines. Indicate to the user** by turning off Continuous Wrap mode.*/static void addWrapNewlines(WindowInfo *window){ int fileLen, i, insertPositions[MAX_PANES], topLines[MAX_PANES]; int horizOffset; Widget text; char *fileString; /* save the insert and scroll positions of each pane */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; insertPositions[i] = TextGetCursorPos(text); TextGetScroll(text, &topLines[i], &horizOffset); } /* Modify the buffer to add wrapping */ fileString = TextGetWrapped(window->textArea, 0, window->buffer->length, &fileLen); BufSetAll(window->buffer, fileString); XtFree(fileString); /* restore the insert and scroll positions of each pane */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; TextSetCursorPos(text, insertPositions[i]); TextSetScroll(text, topLines[i], 0); } /* Show the user that something has happened by turning off Continuous Wrap mode */ XmToggleButtonSetState(window->continuousWrapItem, False, True);}/* * Number of bytes read at once by cmpWinAgainstFile */#define PREFERRED_CMPBUF_LEN 32768/* * Check if the contens of the textBuffer *buf is equal * the contens of the file named fileName. The format of * the file (UNIX/DOS/MAC) is handled properly. * * Return values * 0: no difference found * !0: difference found or could not compare contents. */static int cmpWinAgainstFile(WindowInfo *window, const char *fileName){ char fileString[PREFERRED_CMPBUF_LEN + 2]; struct stat statbuf; int fileLen, restLen, nRead, bufPos, rv, offset, filePos; char pendingCR = 0; int fileFormat = window->fileFormat; char message[MAXPATHLEN+50]; textBuffer *buf = window->buffer; FILE *fp; fp = fopen(fileName, "r"); if (!fp) return (1); if (fstat(fileno(fp), &statbuf) != 0) { fclose(fp); return (1); } fileLen = statbuf.st_size; /* For DOS files, we can't simply check the length */ if (fileFormat != DOS_FILE_FORMAT) { if (fileLen != buf->length) { fclose(fp); return (1); } } else { /* If a DOS file is smaller on disk, it's certainly different */ if (fileLen < buf->length) { fclose(fp); return (1); } } /* For large files, the comparison can take a while. If it takes too long, the user should be given a clue about what is happening. */ sprintf(message, "Comparing externally modified %s ...", window->filename); restLen = min(PREFERRED_CMPBUF_LEN, fileLen); bufPos = 0; filePos = 0; while (restLen > 0) { AllWindowsBusy(message); if (pendingCR) { fileString[0] = pendingCR; offset = 1; } else { offset = 0; } nRead = fread(fileString+offset, sizeof(char), restLen, fp); if (nRead != restLen) { fclose(fp); AllWindowsUnbusy(); return (1); } filePos += nRead; nRead += offset; if (fileFormat == MAC_FILE_FORMAT) ConvertFromMacFileString(fileString, nRead); else if (fileFormat == DOS_FILE_FORMAT) ConvertFromDosFileString(fileString, &nRead, &pendingCR); /* Beware of 0 chars ! */ BufSubstituteNullChars(fileString, nRead, buf); rv = BufCmp(buf, bufPos, nRead, fileString); if (rv) { fclose(fp); AllWindowsUnbusy(); return (rv); } bufPos += nRead; restLen = min(fileLen - filePos, PREFERRED_CMPBUF_LEN); } AllWindowsUnbusy(); fclose(fp); if (pendingCR) { rv = BufCmp(buf, bufPos, 1, &pendingCR); if (rv) { return (rv); } bufPos += 1; } if (bufPos != buf->length) { return (1); } return (0);}static int min(int i1, int i2){ return i1 <= i2 ? i1 : i2;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -