# HG changeset patch # User John W. Eaton # Date 1368931390 14400 # Node ID e1c6ad54259f8817677016f0f3967fb59e757f07 # Parent 2c8dc18fa9c6e034e42e483f21e592e0b83e5541# Parent d3619d4d267cfe733bec1e2b4496af490557ff58 maint: periodic merge of default to classdef diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -76,3 +76,5 @@ 23a7661e529ae9bfc91693618f8c314c31f695ca ss-3-7-2 cc5a7d1233f3acea85648baeb754fc0e8f225225 rc-3-6-4-2 b29b10fbb7448cdfe29322446e1a589e7fe1a40a release-3-6-4 +4e50bd2946d8563d3e201cc04b3ba0720c991b06 ss-3-7-4 +608e307b49149b32a6d09c2f06493d04d3af9be4 ss-3-7-5 diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -19,13 +19,13 @@ ### . AC_PREREQ([2.62]) -AC_INIT([GNU Octave], [3.7.3+], [http://octave.org/bugs.html], [octave]) +AC_INIT([GNU Octave], [3.7.5], [http://octave.org/bugs.html], [octave]) dnl PACKAGE_VERSION is set by the AC_INIT VERSION arg OCTAVE_VERSION="$PACKAGE_VERSION" OCTAVE_API_VERSION_NUMBER="48" OCTAVE_API_VERSION="api-v$OCTAVE_API_VERSION_NUMBER+" -OCTAVE_RELEASE_DATE="2013-04-22" +OCTAVE_RELEASE_DATE="2013-05-14" OCTAVE_COPYRIGHT="Copyright (C) 2013 John W. Eaton and others." AC_SUBST(OCTAVE_VERSION) AC_SUBST(OCTAVE_API_VERSION_NUMBER) @@ -2599,10 +2599,10 @@ fi if test $build_gui = yes; then - AC_CHECK_PROGS(MOC, [moc-qt5 moc-qt4 moc]) - AC_CHECK_PROGS(UIC, [uic-qt5 uic-qt4 uic]) - AC_CHECK_PROGS(RCC, [rcc]) - AC_CHECK_PROGS(LRELEASE, [lrelease-qt5 lrelease-qt4 lrelease]) + AC_CHECK_TOOLS(MOC, [moc-qt5 moc-qt4 moc]) + AC_CHECK_TOOLS(UIC, [uic-qt5 uic-qt4 uic]) + AC_CHECK_TOOLS(RCC, [rcc]) + AC_CHECK_TOOLS(LRELEASE, [lrelease-qt5 lrelease-qt4 lrelease]) if test -n "$MOC" && test -n "$UIC" && test -n "$RCC" && test -n "$LRELEASE"; then AC_DEFINE(HAVE_QT, 1, [Define to 1 if Qt is available (libraries, developer header files, utility programs (moc, uic, rcc, and lrelease))]) @@ -2648,6 +2648,13 @@ OCTAVE_CHECK_FUNC_FINDFIRST_MODERN AC_DEFINE(HAVE_QSCINTILLA, 1, [Define to 1 if the QScintilla library and header files are available]) + + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$QT_CPPFLAGS $CPPFLAGS" + AC_LANG_PUSH(C++) + AC_CHECK_HEADERS([Qsci/qscilexeroctave.h Qsci/qscilexermatlab.h]) + AC_LANG_POP(C++) + CPPFLAGS="$save_CPPFLAGS" fi AC_CHECK_FUNCS([setlocale], [], diff --git a/doc/interpreter/contrib.txi b/doc/interpreter/contrib.txi --- a/doc/interpreter/contrib.txi +++ b/doc/interpreter/contrib.txi @@ -47,81 +47,10 @@ @node Building the Development Sources @section Building the Development Sources -In addition to all the tools (both optional and required) that are -listed in @ref{Build Dependencies} you will need Mercurial, a -distributed version control system (@url{http://mercurial.selenic.com}). -Octave's sources are stored in a Mercurial archive. - -Once you have the required tools installed, you can build Octave by -doing - -@itemize @bullet -@item -Check out a copy of the Octave sources: - -@example -hg clone http://www.octave.org/hg/octave -@end example - -@item -Change to the top-level directory of the newly checked out sources: - -@example -cd octave -@end example - -@item -Generate the necessary configuration files: - -@example -./bootstrap -@end example - -@item -Create a build directory and change to it: - -@example -@group -mkdir build -cd build -@end group -@end example - -By using a separate build directory, you will keep the source directory -clean and it will be easy to completely remove all files generated by -the build. You can also have parallel build trees for different -purposes that all share the same sources. For example, one build tree -may be configured to disable compiler optimization in order to allow for -easier debugging while another may be configured to test building with -other specialized compiler flags. - -@item -Run Octave's configure script from the build directory: - -@example -../configure -@end example - -@item -Run make in the build directory: - -@example -make -@end example - -@end itemize - -Once the build is finished, you will see a message like the following: - -@example -@group -Octave successfully built. Now choose from the following: - - ./run-octave - to run in place to test before installing - make check - to run the tests - make install - to install (PREFIX=...) -@end group -@end example +The directions for building from the Development sources change from +time to time, so you should read the resources for developers on the web +or in the development sources archive. Start here: +@url{http://www.octave.org/get-involved.html}. @node Basics of Generating a Changeset @section Basics of Generating a Changeset diff --git a/doc/interpreter/contributors.in b/doc/interpreter/contributors.in --- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -285,6 +285,7 @@ Stefan van der Walt Peter Van Wieren James R. Van Zandt +Risto Vanhanen Gregory Vanuxem Ivana Varekova Thomas Walter diff --git a/etc/HACKING b/etc/HACKING --- a/etc/HACKING +++ b/etc/HACKING @@ -9,6 +9,29 @@ the savannah source code repository. These requirements do not apply when building from a distribution tarball. +* Quick start + + 1. Install all the required dependencies. Precisely how to do that + depends on what type of system you are using. There are more + details below. + + 2. Clone the Octave sources: + + hg clone http://www.octave.org/hg/octave + + 3. Change to the top-level directory of the Octave source tree and run + the bootstrap script: + + cd octave + ./bootstrap + + 4. Create a build directory, cd to it, then run configure and make: + + mkdir .build + cd .build + ../configure + make + ** Requirements We've opted to keep only the highest-level sources in the repository. @@ -23,6 +46,7 @@ - Flex - Gnulib - GNU Make + - gperf - Gzip - Libtool - Mercurial @@ -220,8 +244,6 @@ m-editor source files for the m-file editor. - octave-adapter souce files for the octave layer for threadsafe - communication with the octave interpreter. qtinfo source files for the Qt texinfo browser. icons icon files that will be compiled into the @@ -304,7 +326,7 @@ jwe@octave.org -Last updated: Thu, 10 Jan 2013 10:46:41 EST +Last updated: Wed, 15 May 2013 03:02:45 EDT ################################################################################ diff --git a/libgui/qterminal/libqterminal/QTerminal.h b/libgui/qterminal/libqterminal/QTerminal.h --- a/libgui/qterminal/libqterminal/QTerminal.h +++ b/libgui/qterminal/libqterminal/QTerminal.h @@ -24,7 +24,7 @@ #define QTERMINAL_H #include -#include +#include #include #include #include @@ -76,6 +76,10 @@ virtual void setCursorColor (bool useForegroundColor, const QColor& color) = 0; +signals: + + void report_status_message (const QString&); + public slots: virtual void copyClipboard (void) = 0; @@ -94,18 +98,32 @@ QTerminal (QWidget *xparent = 0) : QWidget (xparent) { - connect (this, SIGNAL (customContextMenuRequested (QPoint)), - this, SLOT (handleCustomContextMenuRequested (QPoint))); - setContextMenuPolicy (Qt::CustomContextMenu); _contextMenu = new QMenu (this); - QAction *copyAction = _contextMenu->addAction ("Copy"); - QAction *pasteAction = _contextMenu->addAction ("Paste"); + QAction *copyAction + = _contextMenu->addAction (tr ("Copy"), + this, SLOT (copyClipboard ())); + + QAction *pasteAction + = _contextMenu->addAction (tr ("Paste"), + this, SLOT (pasteClipboard ())); + + connect (this, SIGNAL (customContextMenuRequested (QPoint)), + this, SLOT (handleCustomContextMenuRequested (QPoint))); - connect (copyAction, SIGNAL (triggered()), this, SLOT (copyClipboard())); - connect (pasteAction, SIGNAL (triggered()), this, SLOT (pasteClipboard())); + connect (this, SIGNAL (report_status_message (const QString&)), + xparent, SLOT (report_status_message (const QString&))); + + connect (xparent, SIGNAL (settings_changed (const QSettings *)), + this, SLOT (notice_settings (const QSettings *))); + + connect (xparent, SIGNAL (copyClipboard_signal ()), + this, SLOT (copyClipboard ())); + + connect (xparent, SIGNAL (pasteClipboard_signal ()), + this, SLOT (pasteClipboard ())); } private: diff --git a/libgui/qterminal/libqterminal/unix/TerminalView.cpp b/libgui/qterminal/libqterminal/unix/TerminalView.cpp --- a/libgui/qterminal/libqterminal/unix/TerminalView.cpp +++ b/libgui/qterminal/libqterminal/unix/TerminalView.cpp @@ -2264,7 +2264,16 @@ return; QString text = _screenWindow->selectedText(_preserveLineBreaks); - QApplication::clipboard()->setText(text); + + if (text.isEmpty ()) + { + // FIXME -- interrupt is only appropriate here if CTRL-C is bound + // to the copy action. How can we determine that? + + ::raise (SIGINT); + } + else + QApplication::clipboard()->setText(text); } void TerminalView::pasteClipboard() diff --git a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp --- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp +++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp @@ -43,6 +43,7 @@ #define _WIN32_WINNT 0x0500 #include #include +#include #include #include "QWinTerminalImpl.h" @@ -171,6 +172,7 @@ QPoint m_beginSelection; QPoint m_endSelection; + bool m_settingSelection; QColor m_selectionColor; QColor m_cursorColor; @@ -202,7 +204,8 @@ QConsolePrivate::QConsolePrivate (QWinTerminalImpl* parent, const QString& cmd) : q (parent), m_command (cmd), m_hasBlinkingCursor (true), m_cursorType (BlockCursor), m_beginSelection (0, 0), - m_endSelection (0, 0), m_process (NULL), m_inWheelEvent (false) + m_endSelection (0, 0), m_settingSelection (false), + m_process (NULL), m_inWheelEvent (false) { log (NULL); @@ -1177,15 +1180,22 @@ void QWinTerminalImpl::mouseMoveEvent (QMouseEvent *event) { - d->m_endSelection = d->posToCell (event->pos ()); + if (d->m_settingSelection) + { + d->m_endSelection = d->posToCell (event->pos ()); - updateSelection (); + updateSelection (); + } } void QWinTerminalImpl::mousePressEvent (QMouseEvent *event) { if (event->button () == Qt::LeftButton) - d->m_beginSelection = d->posToCell (event->pos ()); + { + d->m_settingSelection = true; + + d->m_beginSelection = d->posToCell (event->pos ()); + } } void QWinTerminalImpl::mouseReleaseEvent (QMouseEvent *event) @@ -1195,6 +1205,8 @@ d->m_endSelection = d->posToCell (event->pos ()); updateSelection (); + + d->m_settingSelection = false; } } @@ -1426,7 +1438,18 @@ { QClipboard *clipboard = QApplication::clipboard (); - clipboard->setText (d->getSelection ()); + QString selection = d->getSelection (); + + if (selection.isEmpty ()) + { + ::raise (SIGINT); + } + else + { + clipboard->setText (selection); + + emit report_status_message (tr ("copied selection to clipboard")); + } } ////////////////////////////////////////////////////////////////////////////// diff --git a/libgui/src/dialog.cc b/libgui/src/dialog.cc --- a/libgui/src/dialog.cc +++ b/libgui/src/dialog.cc @@ -443,6 +443,13 @@ setOption (QFileDialog::DontConfirmOverwrite, false); setConfirmOverwrite(true); } + else if (multimode == "dir") // uigetdir + { + setFileMode (QFileDialog::Directory); + setOption (QFileDialog::ShowDirsOnly, true); + setOption (QFileDialog::HideNameFilterDetails, true); + setAcceptMode (QFileDialog::AcceptOpen); + } else // uigetfile multiselect=off { setFileMode (QFileDialog::ExistingFile); diff --git a/libgui/src/m-editor/file-editor-tab.cc b/libgui/src/m-editor/file-editor-tab.cc --- a/libgui/src/m-editor/file-editor-tab.cc +++ b/libgui/src/m-editor/file-editor-tab.cc @@ -27,9 +27,13 @@ #ifdef HAVE_QSCINTILLA #include -// Not available in the Debian repos yet! -// #include -#include "lexer-octave-gui.h" +#if defined (HAVE_QSCI_QSCILEXEROCTAVE_H) +#define HAVE_LEXER_OCTAVE +#include +#elif defined (HAVE_QSCI_QSCILEXERMATLAB_H) +#define HAVE_LEXER_MATLAB +#include +#endif #include #include #include @@ -210,45 +214,74 @@ { QsciLexer *lexer = _edit_area->lexer (); delete lexer; + lexer = 0; if (_file_name.endsWith (".m") - || _file_name.endsWith (".M") || _file_name.endsWith ("octaverc")) { - lexer = new lexer_octave_gui (); - } - else if (_file_name.endsWith (".c") - || _file_name.endsWith (".cc") - || _file_name.endsWith (".cpp") - || _file_name.endsWith (".cxx") - || _file_name.endsWith (".c++") - || _file_name.endsWith (".h") - || _file_name.endsWith (".hh") - || _file_name.endsWith (".hpp") - || _file_name.endsWith (".h++")) - { - lexer = new QsciLexerCPP (); +#if defined (HAVE_LEXER_OCTAVE) + lexer = new QsciLexerOctave (); +#elif defined (HAVE_LEXER_MATLAB) + lexer = new QsciLexerMatlab (); +#endif } - else if (_file_name.endsWith (".pl")) + + if (! lexer) { - lexer = new QsciLexerPerl (); - } - else if (_file_name.endsWith (".bat")) - { - lexer = new QsciLexerBatch (); + if (_file_name.endsWith (".c") + || _file_name.endsWith (".cc") + || _file_name.endsWith (".cpp") + || _file_name.endsWith (".cxx") + || _file_name.endsWith (".c++") + || _file_name.endsWith (".h") + || _file_name.endsWith (".hh") + || _file_name.endsWith (".hpp") + || _file_name.endsWith (".h++")) + { + lexer = new QsciLexerCPP (); + } + else if (_file_name.endsWith (".pl")) + { + lexer = new QsciLexerPerl (); + } + else if (_file_name.endsWith (".bat")) + { + lexer = new QsciLexerBatch (); + } + else if (_file_name.endsWith (".diff")) + { + lexer = new QsciLexerDiff (); + } + else + { + // FIXME -- why should the bash lexer be the default? + lexer = new QsciLexerBash (); + } } - else if (_file_name.endsWith (".diff")) + + if (lexer) { - lexer = new QsciLexerDiff (); - } - else // Default to bash lexer. - { - lexer = new QsciLexerBash (); + QsciAPIs *apis = new QsciAPIs(lexer); + if (apis) + { + QString keyword; + QStringList keyword_list; + int i; + for (i=1; i<=3; i++) // load the first 3 keyword sets + { + keyword = QString(lexer->keywords (i)); // get list + keyword_list = keyword.split (QRegExp ("\\s+")); // split + for (i = 0; i < keyword_list.size (); i++) // add to API + apis->add (keyword_list.at (i)); + } + apis->prepare (); + } } QSettings *settings = resource_manager::get_settings (); if (settings) lexer->readSettings (*settings); + _edit_area->setLexer (lexer); } @@ -1060,8 +1093,30 @@ _edit_area->setCaretLineVisible (settings->value ("editor/highlightCurrentLine", true).toBool ()); - if (settings->value ("editor/codeCompletion", true).toBool ()) - _edit_area->setAutoCompletionThreshold (1); + if (settings->value ("editor/codeCompletion", true).toBool ()) // auto compl. + { + bool match_keywords = settings->value + ("editor/codeCompletion_keywords",true).toBool (); + bool match_document = settings->value + ("editor/codeCompletion_document",true).toBool (); + + QsciScintilla::AutoCompletionSource source = QsciScintilla::AcsNone; + if (match_keywords) + if (match_document) + source = QsciScintilla::AcsAll; + else + source = QsciScintilla::AcsAPIs; + else + if (match_document) + source = QsciScintilla::AcsDocument; + _edit_area->setAutoCompletionSource (source); + + _edit_area->setAutoCompletionReplaceWord + (settings->value ("editor/codeCompletion_replace",false).toBool ()); + + _edit_area->setAutoCompletionThreshold + (settings->value ("editor/codeCompletion_threshold",2).toInt ()); + } else _edit_area->setAutoCompletionThreshold (-1); diff --git a/libgui/src/m-editor/lexer-octave-gui.cc b/libgui/src/m-editor/lexer-octave-gui.cc deleted file mode 100644 --- a/libgui/src/m-editor/lexer-octave-gui.cc +++ /dev/null @@ -1,185 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_QSCINTILLA - -#include "lexer-octave-gui.h" -#include -#include - -// ----------------------------------------------------- -// Some basic functions -// ----------------------------------------------------- -lexer_octave_gui::lexer_octave_gui (QObject *p) - : QsciLexer (p) -{ - // The API info that is used for auto completion - // TODO: Where to store a file with API info (raw or prepared?)? - // TODO: Also provide infos on octave-forge functions? - // TODO: Also provide infos on function parameters? - // By now, use the keywords-list from syntax highlighting - QString keyword; - QStringList keywordList; - keyword = this->keywords (1); // get whole string with all keywords - keywordList = keyword.split (QRegExp ("\\s+")); // split into single strings - lexer_api = new QsciAPIs (this); - if (lexer_api) - { - for (int i = 0; i < keywordList.size (); i++) // add all keywords to API - lexer_api->add (keywordList.at (i)); - lexer_api->prepare (); // prepare API info ... this may take some time - } -} - -lexer_octave_gui::~lexer_octave_gui() -{ - if (lexer_api) - delete lexer_api; -} - -// ----------------------------------------------------------------------------- -// Redefined functions to make an octave lexer from the abtract class Qscilexer. -// Scintilla has an octave/matlab-lexer but the interface in Qscintilla is -// only available in version 2.5.1. Redefining the following purely virtual -// functions of the class QsciLexer () and the enum of available styles (see -// lexer-octave-gui.h provides the functionality of the octave lexer. -// ----------------------------------------------------------------------------- -const char * -lexer_octave_gui::language() const -{ - return "Octave"; // return the name of the language -} - -const char * -lexer_octave_gui::lexer() const -{ - return "octave"; // return the name of the lexer -} - -QString -lexer_octave_gui::description(int style) const -{ - switch (style) - { - case Default: - return tr("Default"); - case Comment: - return tr("Comment"); - case Command: - return tr("Command"); - case Number: - return tr("Number"); - case Keyword: - return tr("Keyword"); - case SingleQuotedString: - return tr("Single-quoted string"); - case Operator: - return tr("Operator"); - case Identifier: - return tr("Identifier"); - case DoubleQuotedString: - return tr("Double-quoted string"); - } - return QString(); // no valid style, return empty string -} - - -// ----------------------------------------------------- -// The set of default colors -// ----------------------------------------------------- -QColor -lexer_octave_gui::defaultColor (int style) const -{ - switch (style) - { - case Default: - case Operator: - return QColor (0x00,0x00,0x00); - - case Comment: - return QColor (0x00,0x7f,0x00); - - case Command: - return QColor (0x7f,0x7f,0x00); - - case Number: - return QColor (0x00,0x7f,0x7f); - - case Keyword: - return QColor (0x00,0x00,0x7f); - - case SingleQuotedString: - case DoubleQuotedString: - return QColor (0x7f,0x00,0x7f); - } - - return QsciLexer::defaultColor (style); -} - -// ----------------------------------------------------- -// The defaulot fonts -// ----------------------------------------------------- -QFont -lexer_octave_gui::defaultFont (int style) const -{ - QFont f; - - switch (style) - { - case Keyword: - f = QsciLexer::defaultFont (style); - f.setBold(true); - break; - - default: - f = QsciLexer::defaultFont (style); - } - - return f; -} - -// ----------------------------------------------------- -// The style used for braces -// ----------------------------------------------------- -int -lexer_octave_gui::braceStyle() const -{ - return Operator; -} - -// ----------------------------------------------------- -// The set of keywords for highlighting -// ----------------------------------------------------- -const char * -lexer_octave_gui::keywords(int set) const -{ - if (set == 1) - return resource_manager::octave_keywords (); - - return 0; -} - -#endif diff --git a/libgui/src/m-editor/lexer-octave-gui.h b/libgui/src/m-editor/lexer-octave-gui.h deleted file mode 100644 --- a/libgui/src/m-editor/lexer-octave-gui.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifndef LEXEROCTAVE_H -#define LEXEROCTAVE_H - -#include "resource-manager.h" -#include -#include -#include -#include - -class lexer_octave_gui : public QsciLexer -{ - Q_OBJECT - -public: - - enum { - Default = 0, - Comment = 1, - Command = 2, - Number = 3, - Keyword = 4, - SingleQuotedString = 5, - Operator = 6, - Identifier = 7, - DoubleQuotedString = 8 - }; - - - lexer_octave_gui (QObject *parent = 0); - ~lexer_octave_gui (); - virtual const char *keywords (int set) const; - virtual const char *lexer () const; - virtual const char *language () const; - QString description (int style) const; - QColor defaultColor (int style) const; - QFont defaultFont (int style) const; - int braceStyle() const; - -private: - lexer_octave_gui (const lexer_octave_gui &); - lexer_octave_gui &operator= (const lexer_octave_gui &); - QsciAPIs *lexer_api; -}; - -#endif diff --git a/libgui/src/main-window.cc b/libgui/src/main-window.cc --- a/libgui/src/main-window.cc +++ b/libgui/src/main-window.cc @@ -25,6 +25,7 @@ #include #endif +#include #include #include #include @@ -630,6 +631,18 @@ workspace_window->connect_visibility_changed (); } +void +main_window::copyClipboard (void) +{ + emit copyClipboard_signal (); +} + +void +main_window::pasteClipboard (void) +{ + emit pasteClipboard_signal (); +} + // Connect the signals emitted when the Octave thread wants to create // a dialog box of some sort. Perhaps a better place for this would be // as part of the QUIWidgetCreator class. However, mainWindow currently @@ -819,6 +832,7 @@ construct_octave_qt_link (); +#ifdef HAVE_QSCINTILLA connect (this, SIGNAL (insert_debugger_pointer_signal (const QString&, int)), editor_window, @@ -833,6 +847,7 @@ SIGNAL (update_breakpoint_marker_signal (bool, const QString&, int)), editor_window, SLOT (handle_update_breakpoint_marker_request (bool, const QString&, int))); +#endif QDir curr_dir; set_current_working_directory (curr_dir.absolutePath ()); @@ -889,10 +904,12 @@ connect (_octave_qt_link, SIGNAL (exit_debugger_signal ()), this, SLOT (handle_exit_debugger ())); +#ifdef HAVE_QSCINTILLA connect (_octave_qt_link, SIGNAL (edit_file_signal (const QString&)), editor_window, SLOT (handle_edit_file_request (const QString&))); +#endif connect (_octave_qt_link, SIGNAL (insert_debugger_pointer_signal (const QString&, int)), @@ -946,8 +963,6 @@ _open_action = file_menu->addAction (QIcon (":/actions/icons/fileopen.png"), tr ("Open...")); - _open_action->setShortcut (QKeySequence::Open); - _open_action->setShortcutContext (Qt::ApplicationShortcut); #ifdef HAVE_QSCINTILLA file_menu->addMenu (editor_window->get_mru_menu ()); @@ -975,8 +990,10 @@ connect (preferences_action, SIGNAL (triggered ()), this, SLOT (process_settings_dialog_request ())); +#ifdef HAVE_QSCINTILLA connect (_open_action, SIGNAL (triggered ()), editor_window, SLOT (request_open_file ())); +#endif connect (load_workspace_action, SIGNAL (triggered ()), this, SLOT (handle_load_workspace_request ())); @@ -1003,11 +1020,13 @@ QAction *new_figure_action = new_menu->addAction (tr ("Figure")); new_figure_action->setEnabled (true); +#ifdef HAVE_QSCINTILLA connect (_new_script_action, SIGNAL (triggered ()), editor_window, SLOT (request_new_script ())); connect (new_function_action, SIGNAL (triggered ()), editor_window, SLOT (request_new_function ())); +#endif connect (new_figure_action, SIGNAL (triggered ()), this, SLOT (handle_new_figure_request ())); @@ -1026,27 +1045,16 @@ edit_menu->addSeparator (); - _cut_action - = edit_menu->addAction (QIcon (":/actions/icons/editcut.png"), tr ("Cut")); - _cut_action->setShortcut (ctrl_shift + Qt::Key_X); - _copy_action - = edit_menu->addAction (QIcon (":/actions/icons/editcopy.png"), tr ("Copy")); + = edit_menu->addAction (QIcon (":/actions/icons/editcopy.png"), + tr ("Copy"), this, SLOT (copyClipboard ())); _copy_action->setShortcut (ctrl_shift + Qt::Key_C); _paste_action - = edit_menu->addAction (QIcon (":/actions/icons/editpaste.png"), tr ("Paste")); + = edit_menu->addAction (QIcon (":/actions/icons/editpaste.png"), + tr ("Paste"), this, SLOT (pasteClipboard ())); _paste_action->setShortcut (ctrl_shift + Qt::Key_V); - QAction *select_all_action - = edit_menu->addAction (tr ("Select All")); - select_all_action->setEnabled (false); // TODO: Make this work. - - QAction *delete_action - = edit_menu->addAction (tr ("Delete")); - delete_action->setShortcut (Qt::Key_Delete); - delete_action->setEnabled (false); // TODO: Make this work. - edit_menu->addSeparator (); QAction *find_files_action @@ -1064,12 +1072,6 @@ QAction *clear_workspace_action = edit_menu->addAction (tr ("Clear Workspace")); - connect (_copy_action, SIGNAL (triggered()), - command_window, SLOT (copyClipboard ())); - - connect (_paste_action, SIGNAL (triggered()), - command_window, SLOT (pasteClipboard ())); - connect (find_files_action, SIGNAL (triggered()), this, SLOT (find_files ())); @@ -1259,8 +1261,10 @@ connect (file_browser_action, SIGNAL (triggered ()), file_browser_window, SLOT (focus ())); +#ifdef HAVE_QSCINTILLA connect (editor_action, SIGNAL (triggered ()), editor_window, SLOT (focus ())); +#endif connect (documentation_action, SIGNAL (triggered ()), doc_browser_window, SLOT (focus ())); @@ -1334,7 +1338,6 @@ _main_tool_bar->addSeparator (); - _main_tool_bar->addAction (_cut_action); _main_tool_bar->addAction (_copy_action); _main_tool_bar->addAction (_paste_action); _main_tool_bar->addAction (_undo_action); diff --git a/libgui/src/main-window.h b/libgui/src/main-window.h --- a/libgui/src/main-window.h +++ b/libgui/src/main-window.h @@ -86,6 +86,9 @@ void update_breakpoint_marker_signal (bool insert, const QString& file, int line); + void copyClipboard_signal (void); + void pasteClipboard_signal (void); + public slots: void report_status_message (const QString& statusMessage); void handle_save_workspace_request (void); @@ -138,6 +141,9 @@ void write_settings (void); void connect_visibility_changed (void); + void copyClipboard (void); + void pasteClipboard (void); + void connect_uiwidget_links (); void handle_create_dialog (const QString& message, const QString& title, @@ -256,7 +262,6 @@ QAction *_new_script_action; QAction *_open_action; - QAction *_cut_action; QAction *_copy_action; QAction *_paste_action; QAction *_undo_action; diff --git a/libgui/src/module.mk b/libgui/src/module.mk --- a/libgui/src/module.mk +++ b/libgui/src/module.mk @@ -69,8 +69,7 @@ src/m-editor/moc-file-editor-interface.cc \ src/m-editor/moc-file-editor-tab.cc \ src/m-editor/moc-file-editor.cc \ - src/m-editor/moc-find-dialog.cc \ - src/m-editor/moc-lexer-octave-gui.cc + src/m-editor/moc-find-dialog.cc endif octave_gui_MOC += \ @@ -111,7 +110,6 @@ src/m-editor/file-editor-tab.h \ src/m-editor/file-editor.h \ src/m-editor/find-dialog.h \ - src/m-editor/lexer-octave-gui.h \ src/main-window.h \ src/octave-gui.h \ src/octave-main-thread.h \ @@ -136,7 +134,6 @@ src/m-editor/file-editor-tab.cc \ src/m-editor/file-editor.cc \ src/m-editor/find-dialog.cc \ - src/m-editor/lexer-octave-gui.cc \ src/main-window.cc \ src/octave-gui.cc \ src/octave-main-thread.cc \ diff --git a/libgui/src/octave-gui.cc b/libgui/src/octave-gui.cc --- a/libgui/src/octave-gui.cc +++ b/libgui/src/octave-gui.cc @@ -29,6 +29,7 @@ #include +#include #include #if defined (HAVE_SYS_IOCTL_H) @@ -49,12 +50,7 @@ static void dissociate_terminal (void) { -#if ! defined (__WIN32__) || defined (__CYGWIN__) -# if defined (HAVE_SYS_IOCTL_H) && defined (TIOCNOTTY) - - ioctl (0, TIOCNOTTY); - -# else +#if ! (defined (__WIN32__) || defined (__APPLE__)) || defined (__CYGWIN__) pid_t pid = fork (); @@ -77,6 +73,9 @@ { // Parent + // FIXME -- we should catch signals and pass them on to the child + // process in some way, possibly translating SIGINT to SIGTERM. + int status; waitpid (pid, &status, 0); @@ -85,7 +84,6 @@ ? octave_wait::exitstatus (status) : 127); } -# endif #endif } diff --git a/libgui/src/octave-qt-link.cc b/libgui/src/octave-qt-link.cc diff --git a/libgui/src/settings-dialog.cc b/libgui/src/settings-dialog.cc --- a/libgui/src/settings-dialog.cc +++ b/libgui/src/settings-dialog.cc @@ -35,6 +35,15 @@ #ifdef HAVE_QSCINTILLA #include + +#if defined (HAVE_QSCI_QSCILEXEROCTAVE_H) +#define HAVE_LEXER_OCTAVE +#include +#elif defined (HAVE_QSCI_QSCILEXERMATLAB_H) +#define HAVE_LEXER_MATLAB +#include +#endif + #include #include #include @@ -84,6 +93,10 @@ ui->editor_showLineNumbers->setChecked (settings->value ("editor/showLineNumbers",true).toBool () ); ui->editor_highlightCurrentLine->setChecked (settings->value ("editor/highlightCurrentLine",true).toBool () ); ui->editor_codeCompletion->setChecked (settings->value ("editor/codeCompletion",true).toBool () ); + ui->editor_spinbox_ac_threshold->setValue (settings->value ("editor/codeCompletion_threshold",2).toInt ()); + ui->editor_checkbox_ac_keywords->setChecked (settings->value ("editor/codeCompletion_keywords",true).toBool ()); + ui->editor_checkbox_ac_document->setChecked (settings->value ("editor/codeCompletion_document",false).toBool ()); + ui->editor_checkbox_ac_replace->setChecked (settings->value ("editor/codeCompletion_replace",false).toBool ()); ui->editor_longWindowTitle->setChecked (settings->value ("editor/longWindowTitle",false).toBool ()); ui->editor_restoreSession->setChecked (settings->value ("editor/restoreSession",true).toBool ()); ui->terminal_fontName->setCurrentFont (QFont (settings->value ("terminal/fontName","Courier New").toString()) ); @@ -136,9 +149,15 @@ #ifdef HAVE_QSCINTILLA // editor styles: create lexer, read settings, and create dialog elements QsciLexer *lexer; - lexer = new lexer_octave_gui (); +#if defined (HAVE_LEXER_OCTAVE) + lexer = new QsciLexerOctave (); read_lexer_settings (lexer,settings); delete lexer; +#elif defined (HAVE_LEXER_MATLAB) + lexer = new QsciLexerMatlab (); + read_lexer_settings (lexer,settings); + delete lexer; +#endif lexer = new QsciLexerCPP (); read_lexer_settings (lexer,settings); delete lexer; @@ -359,6 +378,10 @@ settings->setValue ("editor/showLineNumbers", ui->editor_showLineNumbers->isChecked ()); settings->setValue ("editor/highlightCurrentLine", ui->editor_highlightCurrentLine->isChecked ()); settings->setValue ("editor/codeCompletion", ui->editor_codeCompletion->isChecked ()); + settings->setValue ("editor/codeCompletion_threshold", ui->editor_spinbox_ac_threshold->value ()); + settings->setValue ("editor/codeCompletion_keywords", ui->editor_checkbox_ac_keywords->isChecked ()); + settings->setValue ("editor/codeCompletion_document", ui->editor_checkbox_ac_document->isChecked ()); + settings->setValue ("editor/codeCompletion_replace", ui->editor_checkbox_ac_replace->isChecked ()); settings->setValue ("editor/longWindowTitle", ui->editor_longWindowTitle->isChecked()); settings->setValue ("editor/restoreSession", ui->editor_restoreSession->isChecked ()); settings->setValue ("terminal/fontSize", ui->terminal_fontSize->value()); @@ -392,9 +415,15 @@ #ifdef HAVE_QSCINTILLA // editor styles: create lexer, get dialog contents, and write settings QsciLexer *lexer; - lexer = new lexer_octave_gui (); +#if defined (HAVE_LEXER_OCTAVE) + lexer = new QsciLexerOctave (); write_lexer_settings (lexer,settings); delete lexer; +#elif defined (HAVE_LEXER_MATLAB) + lexer = new QsciLexerMatlab (); + write_lexer_settings (lexer,settings); + delete lexer; +#endif lexer = new QsciLexerCPP (); write_lexer_settings (lexer,settings); delete lexer; diff --git a/libgui/src/settings-dialog.h b/libgui/src/settings-dialog.h --- a/libgui/src/settings-dialog.h +++ b/libgui/src/settings-dialog.h @@ -25,8 +25,9 @@ #include #include + #ifdef HAVE_QSCINTILLA -#include "lexer-octave-gui.h" +class QsciLexer; #endif namespace Ui diff --git a/libgui/src/settings-dialog.ui b/libgui/src/settings-dialog.ui --- a/libgui/src/settings-dialog.ui +++ b/libgui/src/settings-dialog.ui @@ -32,7 +32,7 @@ - 3 + 0 @@ -196,10 +196,7 @@ - - - - + @@ -221,19 +218,6 @@ - - - true - - - Code completion - - - false - - - - Show complete path in window title @@ -247,6 +231,144 @@ + + + + + + 6 + + + + + false + + + Characters before list with suggestions is displayed + + + + + + + false + + + + + + + + + + + + 1 + + + 6 + + + 2 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + false + + + Match keywords + + + true + + + + + + + false + + + Match words in document + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + true + + + Code completion + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 0 + + + + + + + + false + + + Replace the rest of the actual word by suggested word + + + + + @@ -918,5 +1040,85 @@ + + editor_codeCompletion + toggled(bool) + editor_label_ac_threshold + setEnabled(bool) + + + 83 + 223 + + + 288 + 223 + + + + + editor_codeCompletion + toggled(bool) + editor_spinbox_ac_threshold + setEnabled(bool) + + + 83 + 223 + + + 412 + 223 + + + + + editor_codeCompletion + toggled(bool) + editor_checkbox_ac_keywords + setEnabled(bool) + + + 83 + 170 + + + 238 + 201 + + + + + editor_codeCompletion + toggled(bool) + editor_checkbox_ac_document + setEnabled(bool) + + + 83 + 170 + + + 390 + 201 + + + + + editor_codeCompletion + toggled(bool) + editor_checkbox_ac_replace + setEnabled(bool) + + + 83 + 170 + + + 427 + 229 + + + diff --git a/libgui/src/terminal-dock-widget.cc b/libgui/src/terminal-dock-widget.cc --- a/libgui/src/terminal-dock-widget.cc +++ b/libgui/src/terminal-dock-widget.cc @@ -36,21 +36,8 @@ setObjectName ("TerminalDockWidget"); setWindowIcon (QIcon(":/actions/icons/logo.png")); setWindowTitle (tr ("Command Window")); + setWidget (terminal); - - connect (this, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_visibility (bool))); - - // Forward signals to QTerminal widget. - - connect (this, SIGNAL (notice_settings_signal (const QSettings *)), - terminal, SLOT (notice_settings (const QSettings *))); - - connect (this, SIGNAL (copyClipboard_signal (void)), - terminal, SLOT (copyClipboard (void))); - - connect (this, SIGNAL (pasteClipboard_signal (void)), - terminal, SLOT (pasteClipboard (void))); } bool @@ -62,24 +49,6 @@ } void -terminal_dock_widget::notice_settings (const QSettings *settings) -{ - emit notice_settings_signal (settings); -} - -void -terminal_dock_widget::copyClipboard (void) -{ - emit copyClipboard_signal (); -} - -void -terminal_dock_widget::pasteClipboard (void) -{ - emit pasteClipboard_signal (); -} - -void terminal_dock_widget::focus (void) { octave_dock_widget::focus (); diff --git a/libgui/src/terminal-dock-widget.h b/libgui/src/terminal-dock-widget.h --- a/libgui/src/terminal-dock-widget.h +++ b/libgui/src/terminal-dock-widget.h @@ -39,26 +39,8 @@ bool has_focus (void) const; -signals: - -public slots: - - void notice_settings (const QSettings *settings); - - void copyClipboard (void); - - void pasteClipboard (void); - void focus (void); -signals: - - void notice_settings_signal (const QSettings *settings); - - void copyClipboard_signal (void); - - void pasteClipboard_signal (void); - private: QTerminal *terminal; diff --git a/libinterp/interp-core/ls-mat5.cc b/libinterp/interp-core/ls-mat5.cc --- a/libinterp/interp-core/ls-mat5.cc +++ b/libinterp/interp-core/ls-mat5.cc @@ -81,6 +81,7 @@ #include #endif +#define READ_PAD(is_small_data_element, l) ((is_small_data_element) ? 4 : (((l)+7)/8)*8) #define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8) #define INT8(l) ((l) == miINT8 || (l) == miUINT8 || (l) == miUTF8) @@ -373,7 +374,7 @@ \ std::streampos tmp_pos; \ \ - if (read_mat5_tag (is, swap, type, len)) \ + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) \ { \ error ("load: reading matrix data for '%s'", retval.c_str ()); \ goto data_read_error; \ @@ -390,14 +391,15 @@ goto data_read_error; \ } \ \ - is.seekg (tmp_pos + static_cast (PAD (len))); \ + is.seekg (tmp_pos + static_cast\ + (READ_PAD (is_small_data_element, len))); \ \ if (imag) \ { \ /* We don't handle imag integer types, convert to an array */ \ NDArray im (dims); \ \ - if (read_mat5_tag (is, swap, type, len)) \ + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) \ { \ error ("load: reading matrix data for '%s'", \ retval.c_str ()); \ @@ -427,10 +429,12 @@ } // Read one element tag from stream IS, -// place the type code in TYPE and the byte count in BYTES +// place the type code in TYPE, the byte count in BYTES and true (false) to +// IS_SMALL_DATA_ELEMENT if the tag is 4 (8) bytes long. // return nonzero on error static int -read_mat5_tag (std::istream& is, bool swap, int32_t& type, int32_t& bytes) +read_mat5_tag (std::istream& is, bool swap, int32_t& type, int32_t& bytes, + bool& is_small_data_element) { unsigned int upper; int32_t temp; @@ -448,6 +452,7 @@ { // "compressed" format bytes = upper; + is_small_data_element = true; } else { @@ -456,6 +461,7 @@ if (swap) swap_bytes<4> (&temp); bytes = temp; + is_small_data_element = false; } return 0; @@ -509,10 +515,11 @@ else flt_fmt = oct_mach_info::flt_fmt_ieee_little_endian; - // element type and length + // element type, length and small data element flag int32_t type = 0; int32_t element_length; - if (read_mat5_tag (is, swap, type, element_length)) + bool is_small_data_element; + if (read_mat5_tag (is, swap, type, element_length, is_small_data_element)) return retval; // EOF if (type == miCOMPRESSED) @@ -623,7 +630,8 @@ // array flags subelement int32_t len; - if (read_mat5_tag (is, swap, type, len) || type != miUINT32 || len != 8) + if (read_mat5_tag (is, swap, type, len, is_small_data_element) || + type != miUINT32 || len != 8 || is_small_data_element) { error ("load: invalid array flags subelement"); goto early_read_error; @@ -649,7 +657,8 @@ { int32_t dim_len; - if (read_mat5_tag (is, swap, type, dim_len) || type != miINT32) + if (read_mat5_tag (is, swap, type, dim_len, is_small_data_element) || + type != miINT32) { error ("load: invalid dimensions array subelement"); goto early_read_error; @@ -665,7 +674,8 @@ } std::streampos tmp_pos = is.tellg (); - is.seekg (tmp_pos + static_cast (PAD (dim_len) - dim_len)); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, dim_len) - dim_len)); } else { @@ -675,7 +685,7 @@ dims(1) = 1; } - if (read_mat5_tag (is, swap, type, len) || !INT8(type)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element) || !INT8(type)) { error ("load: invalid array name subelement"); goto early_read_error; @@ -693,7 +703,8 @@ if (! is.read (name, len )) goto data_read_error; - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); } name[len] = '\0'; @@ -757,7 +768,7 @@ // row indices std::streampos tmp_pos; - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading sparse row data for '%s'", retval.c_str ()); goto data_read_error; @@ -774,10 +785,11 @@ goto data_read_error; } - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); // col indices - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading sparse column data for '%s'", retval.c_str ()); goto data_read_error; @@ -794,10 +806,11 @@ goto data_read_error; } - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); // real data subelement - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading sparse matrix data for '%s'", retval.c_str ()); goto data_read_error; @@ -821,14 +834,15 @@ goto data_read_error; } - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); // imaginary data subelement if (imag) { NDArray im (dim_vector (static_cast (nnz), 1)); - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading sparse matrix data for '%s'", retval.c_str ()); goto data_read_error; @@ -1060,7 +1074,8 @@ { int32_t fn_type; int32_t fn_len; - if (read_mat5_tag (is, swap, fn_type, fn_len) || !INT8(fn_type)) + if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element) || + !INT8(fn_type)) { error ("load: invalid field name subelement"); goto data_read_error; @@ -1075,8 +1090,8 @@ if (! is.read (elname, fn_len)) goto data_read_error; - is.seekg (tmp_pos + - static_cast (PAD (fn_len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, fn_len))); } elname[fn_len] = '\0'; @@ -1121,7 +1136,8 @@ { isclass = true; - if (read_mat5_tag (is, swap, type, len) || !INT8(type)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element) || + !INT8(type)) { error ("load: invalid class name"); goto skip_ahead; @@ -1137,7 +1153,8 @@ if (! is.read (name, len )) goto data_read_error; - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); } name[len] = '\0'; @@ -1157,7 +1174,8 @@ // be 32. We read and use the actual value, on the theory // that eventually someone will recognize that's a waste of // space. - if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT32) + if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element) || + fn_type != miINT32) { error ("load: invalid field name length subelement"); goto data_read_error; @@ -1171,7 +1189,8 @@ // field name subelement. The length of this subelement tells // us how many fields there are. - if (read_mat5_tag (is, swap, fn_type, fn_len) || !INT8(fn_type)) + if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element) || + !INT8(fn_type)) { error ("load: invalid field name subelement"); goto data_read_error; @@ -1181,7 +1200,7 @@ if (n_fields > 0) { - fn_len = PAD (fn_len); + fn_len = READ_PAD (is_small_data_element, fn_len); OCTAVE_LOCAL_BUFFER (char, elname, fn_len); @@ -1320,7 +1339,7 @@ std::streampos tmp_pos; - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading matrix data for '%s'", retval.c_str ()); goto data_read_error; @@ -1337,7 +1356,8 @@ goto data_read_error; } - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); if (imag) { @@ -1345,7 +1365,7 @@ FloatNDArray im (dims); - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading matrix data for '%s'", retval.c_str ()); goto data_read_error; @@ -1386,7 +1406,7 @@ std::streampos tmp_pos; - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading matrix data for '%s'", retval.c_str ()); goto data_read_error; @@ -1403,7 +1423,8 @@ goto data_read_error; } - is.seekg (tmp_pos + static_cast (PAD (len))); + is.seekg (tmp_pos + static_cast + (READ_PAD (is_small_data_element, len))); if (logicalvar) { @@ -1424,7 +1445,7 @@ NDArray im (dims); - if (read_mat5_tag (is, swap, type, len)) + if (read_mat5_tag (is, swap, type, len, is_small_data_element)) { error ("load: reading matrix data for '%s'", retval.c_str ()); goto data_read_error; diff --git a/libinterp/parse-tree/lex.ll b/libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll +++ b/libinterp/parse-tree/lex.ll @@ -147,13 +147,31 @@ } \ while (0) +#define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK) \ + \ + do \ + { \ + curr_lexer->lexer_debug (PATTERN); \ + \ + if (curr_lexer->previous_token_may_be_command ()) \ + { \ + yyless (0); \ + curr_lexer->push_start_state (COMMAND_START); \ + } \ + else \ + { \ + return curr_lexer->handle_incompatible_op (PATTERN, TOK, false); \ + } \ + } \ + while (0) + #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT) \ \ do \ { \ curr_lexer->lexer_debug (PATTERN); \ \ - if (curr_lexer->looks_like_command_arg ()) \ + if (curr_lexer->previous_token_may_be_command ()) \ { \ yyless (0); \ curr_lexer->push_start_state (COMMAND_START); \ @@ -737,13 +755,21 @@ {IDENT}@{IDENT}.{IDENT} { curr_lexer->lexer_debug ("{IDENT}@{IDENT}|{IDENT}@{IDENT}.{IDENT}"); - int id_tok = curr_lexer->handle_superclass_identifier (); - - if (id_tok >= 0) + if (curr_lexer->previous_token_may_be_command ()) + { + yyless (0); + curr_lexer->push_start_state (COMMAND_START); + } + else { - curr_lexer->looking_for_object_index = true; - - return curr_lexer->count_token_internal (id_tok); + int id_tok = curr_lexer->handle_superclass_identifier (); + + if (id_tok >= 0) + { + curr_lexer->looking_for_object_index = true; + + return curr_lexer->count_token_internal (id_tok); + } } } @@ -755,13 +781,22 @@ \?{IDENT}\.{IDENT} { curr_lexer->lexer_debug ("\\?{IDENT}|\\?{IDENT}\\.{IDENT}"); - int id_tok = curr_lexer->handle_meta_identifier (); - - if (id_tok >= 0) + if (curr_lexer->previous_token_may_be_command () + && curr_lexer->space_follows_previous_token ()) + { + yyless (0); + curr_lexer->push_start_state (COMMAND_START); + } + else { - curr_lexer->looking_for_object_index = true; - - return curr_lexer->count_token_internal (id_tok); + int id_tok = curr_lexer->handle_meta_identifier (); + + if (id_tok >= 0) + { + curr_lexer->looking_for_object_index = true; + + return curr_lexer->count_token_internal (id_tok); + } } } @@ -828,6 +863,12 @@ yyless (0); curr_lexer->push_start_state (COMMAND_START); } + else if (curr_lexer->at_beginning_of_statement) + { + curr_lexer->current_input_column++; + int retval = curr_lexer->handle_string ('\''); + return curr_lexer->count_token_internal (retval); + } else { int tok = curr_lexer->previous_token_value (); @@ -996,37 +1037,8 @@ return curr_lexer->handle_op (".'", TRANSPOSE, false); } -"++" { - curr_lexer->lexer_debug ("++"); - - int tok = curr_lexer->handle_incompatible_unary_op (PLUS_PLUS, false); - - if (tok < 0) - { - yyless (0); - curr_lexer->xunput (','); - // Adjust for comma that was not really in the input stream. - curr_lexer->current_input_column--; - } - else - return tok; - } - -"--" { - curr_lexer->lexer_debug ("--"); - - int tok = curr_lexer->handle_incompatible_unary_op (MINUS_MINUS, false); - - if (tok < 0) - { - yyless (0); - curr_lexer->xunput (','); - // Adjust for comma that was not really in the input stream. - curr_lexer->current_input_column--; - } - else - return tok; - } +"++" { CMD_OR_UNARY_OP ("++", PLUS_PLUS, false); } +"--" { CMD_OR_UNARY_OP ("--", MINUS_MINUS, false); } "(" { curr_lexer->lexer_debug ("("); @@ -1119,24 +1131,24 @@ return curr_lexer->handle_op ("=", '='); } -"+=" { return curr_lexer->handle_incompatible_op ("+=", ADD_EQ); } -"-=" { return curr_lexer->handle_incompatible_op ("-=", SUB_EQ); } -"*=" { return curr_lexer->handle_incompatible_op ("*=", MUL_EQ); } -"/=" { return curr_lexer->handle_incompatible_op ("/=", DIV_EQ); } -"\\=" { return curr_lexer->handle_incompatible_op ("\\=", LEFTDIV_EQ); } -".+=" { return curr_lexer->handle_incompatible_op (".+=", ADD_EQ); } -".-=" { return curr_lexer->handle_incompatible_op (".-=", SUB_EQ); } -".*=" { return curr_lexer->handle_incompatible_op (".*=", EMUL_EQ); } -"./=" { return curr_lexer->handle_incompatible_op ("./=", EDIV_EQ); } -".\\=" { return curr_lexer->handle_incompatible_op (".\\=", ELEFTDIV_EQ); } -"^=" { return curr_lexer->handle_incompatible_op ("^=", POW_EQ); } -"**=" { return curr_lexer->handle_incompatible_op ("^=", POW_EQ); } -".^=" { return curr_lexer->handle_incompatible_op (".^=", EPOW_EQ); } -".**=" { return curr_lexer->handle_incompatible_op (".^=", EPOW_EQ); } -"&=" { return curr_lexer->handle_incompatible_op ("&=", AND_EQ); } -"|=" { return curr_lexer->handle_incompatible_op ("|=", OR_EQ); } -"<<=" { return curr_lexer->handle_incompatible_op ("<<=", LSHIFT_EQ); } -">>=" { return curr_lexer->handle_incompatible_op (">>=", RSHIFT_EQ); } +"+=" { CMD_OR_COMPUTED_ASSIGN_OP ("+=", ADD_EQ); } +"-=" { CMD_OR_COMPUTED_ASSIGN_OP ("-=", SUB_EQ); } +"*=" { CMD_OR_COMPUTED_ASSIGN_OP ("*=", MUL_EQ); } +"/=" { CMD_OR_COMPUTED_ASSIGN_OP ("/=", DIV_EQ); } +"\\=" { CMD_OR_COMPUTED_ASSIGN_OP ("\\=", LEFTDIV_EQ); } +".+=" { CMD_OR_COMPUTED_ASSIGN_OP (".+=", ADD_EQ); } +".-=" { CMD_OR_COMPUTED_ASSIGN_OP (".-=", SUB_EQ); } +".*=" { CMD_OR_COMPUTED_ASSIGN_OP (".*=", EMUL_EQ); } +"./=" { CMD_OR_COMPUTED_ASSIGN_OP ("./=", EDIV_EQ); } +".\\=" { CMD_OR_COMPUTED_ASSIGN_OP (".\\=", ELEFTDIV_EQ); } +"^=" { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); } +"**=" { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); } +".^=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); } +".**=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); } +"&=" { CMD_OR_COMPUTED_ASSIGN_OP ("&=", AND_EQ); } +"|=" { CMD_OR_COMPUTED_ASSIGN_OP ("|=", OR_EQ); } +"<<=" { CMD_OR_COMPUTED_ASSIGN_OP ("<<=", LSHIFT_EQ); } +">>=" { CMD_OR_COMPUTED_ASSIGN_OP (">>=", RSHIFT_EQ); } %{ // In Matlab, '{' may also trigger command syntax. diff --git a/libinterp/parse-tree/oct-parse.in.yy b/libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy +++ b/libinterp/parse-tree/oct-parse.in.yy @@ -527,9 +527,9 @@ } ; -anon_fcn_handle : '@' param_list statement +anon_fcn_handle : '@' param_list stmt_begin statement { - $$ = parser.make_anon_fcn_handle ($2, $3); + $$ = parser.make_anon_fcn_handle ($2, $4); lexer.nesting_level.remove (); } ; @@ -868,11 +868,11 @@ } ; -if_cmd_list1 : expression opt_sep opt_list +if_cmd_list1 : expression stmt_begin opt_sep opt_list { $1->mark_braindead_shortcircuit (lexer.fcn_file_full_name); - $$ = parser.start_if_command ($1, $3); + $$ = parser.start_if_command ($1, $4); } | if_cmd_list1 elseif_clause { @@ -881,11 +881,11 @@ } ; -elseif_clause : ELSEIF stash_comment opt_sep expression opt_sep opt_list +elseif_clause : ELSEIF stash_comment opt_sep expression stmt_begin opt_sep opt_list { $4->mark_braindead_shortcircuit (lexer.fcn_file_full_name); - $$ = parser.make_elseif_clause ($1, $4, $6, $2); + $$ = parser.make_elseif_clause ($1, $4, $7, $2); } ; @@ -926,8 +926,8 @@ } ; -switch_case : CASE stash_comment opt_sep expression opt_sep opt_list - { $$ = parser.make_switch_case ($1, $4, $6, $2); } +switch_case : CASE stash_comment opt_sep expression stmt_begin opt_sep opt_list + { $$ = parser.make_switch_case ($1, $4, $7, $2); } ; default_case : OTHERWISE stash_comment opt_sep opt_list @@ -940,11 +940,11 @@ // Looping // ======= -loop_command : WHILE stash_comment expression opt_sep opt_list END +loop_command : WHILE stash_comment expression stmt_begin opt_sep opt_list END { $3->mark_braindead_shortcircuit (lexer.fcn_file_full_name); - if (! ($$ = parser.make_while_command ($1, $3, $5, $6, $2))) + if (! ($$ = parser.make_while_command ($1, $3, $6, $7, $2))) ABORT_PARSE; } | DO stash_comment opt_sep opt_list UNTIL expression @@ -952,10 +952,10 @@ if (! ($$ = parser.make_do_until_command ($5, $4, $6, $2))) ABORT_PARSE; } - | FOR stash_comment assign_lhs '=' expression opt_sep opt_list END + | FOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END { if (! ($$ = parser.make_for_command (FOR, $1, $3, $5, 0, - $7, $8, $2))) + $8, $9, $2))) ABORT_PARSE; } | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END @@ -964,10 +964,10 @@ $9, $10, $2))) ABORT_PARSE; } - | PARFOR stash_comment assign_lhs '=' expression opt_sep opt_list END + | PARFOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END { if (! ($$ = parser.make_for_command (PARFOR, $1, $3, $5, - 0, $7, $8, $2))) + 0, $8, $9, $2))) ABORT_PARSE; } | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END @@ -1496,6 +1496,10 @@ // Miscellaneous // ============= +stmt_begin : // empty + { lexer.at_beginning_of_statement = true; } + ; + stash_comment : // empty { $$ = octave_comment_buffer::get_comment (); } ; diff --git a/libinterp/parse-tree/pt-fcn-handle.cc b/libinterp/parse-tree/pt-fcn-handle.cc --- a/libinterp/parse-tree/pt-fcn-handle.cc +++ b/libinterp/parse-tree/pt-fcn-handle.cc @@ -159,6 +159,19 @@ %! g = @(f, x) h (x); %! f = @() g (@(x) h, pi); %! assert (f () == sin (pi)); + +The next two tests are intended to test parsing of a character string +vs. hermitian operator at the beginning of an anonymous function +expression. The use of ' for the character string and the spacing is +intentional, so don't change it. + +%!test +%! f = @() 'foo'; +%! assert (f (), 'foo'); + +%!test +%! f = @()'foo'; +%! assert (f (), 'foo'); */ octave_value_list diff --git a/libinterp/parse-tree/pt-idx.cc b/libinterp/parse-tree/pt-idx.cc --- a/libinterp/parse-tree/pt-idx.cc +++ b/libinterp/parse-tree/pt-idx.cc @@ -216,7 +216,12 @@ octave_value t = df->rvalue1 (); if (! error_state) - fn = t.string_value (); + { + if (t.is_string () && t.rows () == 1) + fn = t.string_value (); + else + error ("dynamic structure field names must be character strings"); + } } else panic_impossible (); diff --git a/m4/acinclude.m4 b/m4/acinclude.m4 --- a/m4/acinclude.m4 +++ b/m4/acinclude.m4 @@ -1578,6 +1578,7 @@ reconstruct oct-gperf.h " OCTAVE_CONFIGURE_WARNING([warn_gperf]) + GPERF='$(top_srcdir)/build-aux/missing gperf' fi AC_SUBST(GPERF) ]) diff --git a/scripts/io/dlmwrite.m b/scripts/io/dlmwrite.m --- a/scripts/io/dlmwrite.m +++ b/scripts/io/dlmwrite.m @@ -83,7 +83,7 @@ ## 2002-03-08 Paul Kienzle ## * Initial revision ## 2005-11-27 Bill Denney -## * Significant modifications of the input arguements for additional +## * Significant modifications of the input arguments for additional ## functionality. function dlmwrite (file, M, varargin) diff --git a/scripts/io/importdata.m b/scripts/io/importdata.m --- a/scripts/io/importdata.m +++ b/scripts/io/importdata.m @@ -1,4 +1,4 @@ -## Copyright (C) 2012 Erik Kjellson +## Copyright (C) 2012-2013 Erik Kjellson ## ## This file is part of Octave. ## @@ -59,7 +59,6 @@ ## @seealso{textscan, dlmread, csvread, load} ## @end deftypefn -## Author: Erik Kjellson function [output, delimiter, header_rows] = importdata (varargin) @@ -193,8 +192,8 @@ ## Read file into string and count the number of header rows file_content = fileread (fname); - ## Split the file into rows (using \r\n or \n as delimiters between rows). - file_content_rows = regexp (file_content, "\r?\n", "split"); + ## Split the file into rows (using \n and/or \r as delimiters between rows). + file_content_rows = regexp (file_content, "\n|\n\r|\r|\r\n", "split"); ## FIXME: guess delimiter, if it isn't defined if (isempty (delimiter)) @@ -434,3 +433,16 @@ %! assert (d, "\t"); %! assert (h, 0); +%!test +%! # CR for line breaks +%! A = [3.1 -7.2 0; 0.012 6.5 128]; +%! fn = tmpnam (); +%! fid = fopen (fn, "w"); +%! fputs (fid, "3.1\t-7.2\t0\r0.012\t6.5\t128"); +%! fclose (fid); +%! [a,d,h] = importdata (fn, "\\t"); +%! unlink (fn); +%! assert (a, A); +%! assert (d, "\t"); +%! assert (h, 0); + diff --git a/scripts/miscellaneous/orderfields.m b/scripts/miscellaneous/orderfields.m --- a/scripts/miscellaneous/orderfields.m +++ b/scripts/miscellaneous/orderfields.m @@ -153,7 +153,7 @@ else n = numel (s1); for i = 1:numel (names) - el = names(i); + el = names{i}; [t(1:n).(el)] = s1(:).(el); endfor ## inherit dimensions diff --git a/scripts/optimization/optimget.m b/scripts/optimization/optimget.m --- a/scripts/optimization/optimget.m +++ b/scripts/optimization/optimget.m @@ -33,12 +33,18 @@ endif opts = __all_opts__ (); - idx = lookup (tolower (opts), tolower (parname), "m"); + idx = strncmpi (opts, parname, numel (parname)); + + nmatch = sum (idx); - if (idx) + if (nmatch == 1) parname = opts{idx}; + elseif (nmatch == 0) + warning ("unrecognized option: %s", parname); else - warning ("unrecognized option: %s", parname); + fmt = sprintf ("ambiguous option: %%s (%s%%s)", + repmat ("%s, ", 1, nmatch-1)); + warning (fmt, parname, opts{idx}); endif if (isfield (options, parname)) retval = options.(parname); @@ -50,3 +56,12 @@ endfunction +%!error optimget () + +%!shared opts +%! opts = optimset ("tolx", 0.1, "maxit", 100); +%!assert (optimget (opts, "TolX"), 0.1); +%!assert (optimget (opts, "maxit"), 100); +%!assert (optimget (opts, "MaxITer"), 100); +%!warning (optimget (opts, "Max")); +%!warning (optimget (opts, "foobar")); diff --git a/scripts/optimization/optimset.m b/scripts/optimization/optimset.m --- a/scripts/optimization/optimset.m +++ b/scripts/optimization/optimset.m @@ -131,17 +131,20 @@ fnames = fieldnames (old); ## skip validation if we're in the internal query validation = ! isempty (opts); - lopts = tolower (opts); for [val, key] = new if (validation) ## Case insensitive lookup in all options. - i = lookup (lopts, tolower (key)); + i = strncmpi (opts, key, length (key)); + nmatch = sum (i); ## Validate option. - if (i > 0 && strcmpi (opts{i}, key)) - ## Use correct case. - key = opts{i}; + if (nmatch == 1) + key = opts{find (i)}; + elseif (nmatch == 0) + warning ("unrecognized option: %s", key); else - warning ("unrecognized option: %s", key); + fmt = sprintf ("ambiguous option: %%s (%s%%s)", + repmat ("%s, ", 1, nmatch-1)); + warning (fmt, key, opts{i}); endif endif old.(key) = val; @@ -165,6 +168,7 @@ %!assert (optimget (optimset ("tolx", 1e-2), "tOLx"), 1e-2) %!assert (isfield (optimset ("tolFun", 1e-3), "TolFun")) +%!warning (optimset ("Max", 10)); +%!warning (optimset ("foobar", 13)); %!error (optimset ("%NOT_A_REAL_FUNCTION_NAME%")) - diff --git a/scripts/plot/findobj.m b/scripts/plot/findobj.m --- a/scripts/plot/findobj.m +++ b/scripts/plot/findobj.m @@ -185,6 +185,9 @@ endwhile numpairs = np - 1; + if (~ isempty (logicaloperator)) + logicaloperator = shift (logicaloperator, 1); + endif ## Load all objects which qualify for being searched. idepth = 0; @@ -243,6 +246,16 @@ h = reshape (h, [numel(h), 1]); endfunction +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! h = plot (1:10); +%! set (h, "tag", "foobar") +%! g = findobj (gcf (), "tag", "foobar", "type", "line", "color", [0 0 1]); +%! assert (g, h) +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect %!test %! hf = figure ("visible", "off"); @@ -257,3 +270,21 @@ %! close (hf); %! end_unwind_protect +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! subplot (2, 2, 1) +%! imagesc (rand (10)) +%! subplot (2, 2, 2) +%! surf (peaks) +%! subplot (2, 2, 3) +%! contour (peaks) +%! subplot (2, 2, 4) +%! plot (peaks) +%! h1 = findobj (gcf (), "-regexp", "Type", "image|surface|hggroup"); +%! h2 = findobj (gcf (), "Type", "image", "-or", "Type", "surface", "-or", "Type", "hggroup"); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect +%! assert (h2, h1) + diff --git a/scripts/plot/ndgrid.m b/scripts/plot/ndgrid.m --- a/scripts/plot/ndgrid.m +++ b/scripts/plot/ndgrid.m @@ -35,11 +35,11 @@ function varargout = ndgrid (varargin) if (nargin == 1) - n = max ([nargout, 2]); + n = max ([nargout, 1]); ## If only one input argument is given, repeat it n-times varargin(1:n) = varargin(1); - elseif (nargin >= nargout) - n = max ([nargin, 2]); + elseif (nargin > 0 && nargin >= nargout) + n = max ([nargin, 1]); else error ("ndgrid: wrong number of input arguments"); endif @@ -72,6 +72,17 @@ %!test +%! x = 1:3; +%! assert (isequal (ndgrid (x), x(:))); + +%!test +%! x = 1:3; +%! [XX, YY] = ndgrid (x); +%! assert (size_equal (XX, YY)); +%! assert (isequal (XX, repmat(x(:), 1, numel(x)))); +%! assert (isequal (YY, repmat(x, numel(x), 1))); + +%!test %! x = 1:2; %! y = 1:3; %! z = 1:4; diff --git a/scripts/plot/uigetdir.m b/scripts/plot/uigetdir.m --- a/scripts/plot/uigetdir.m +++ b/scripts/plot/uigetdir.m @@ -30,16 +30,18 @@ function dirname = uigetdir (init_path = pwd, dialog_name = "Select Directory to Open") - defaulttoolkit = get (0, "defaultfigure__graphics_toolkit__"); - funcname = ["__uigetdir_", defaulttoolkit, "__"]; - functype = exist (funcname); - if (! __is_function__ (funcname)) - funcname = "__uigetdir_fltk__"; + if (! __octave_link_enabled__ ()) + defaulttoolkit = get (0, "defaultfigure__graphics_toolkit__"); + funcname = ["__uigetdir_", defaulttoolkit, "__"]; + functype = exist (funcname); if (! __is_function__ (funcname)) - error ("uigetdir: fltk graphics toolkit required"); - elseif (! strcmp (defaulttoolkit, "gnuplot")) - warning ("uigetdir: no implementation for toolkit '%s', using 'fltk' instead", - defaulttoolkit); + funcname = "__uigetdir_fltk__"; + if (! __is_function__ (funcname)) + error ("uigetdir: fltk graphics toolkit required"); + elseif (! strcmp (defaulttoolkit, "gnuplot")) + warning ("uigetdir: no implementation for toolkit '%s', using 'fltk' instead", + defaulttoolkit); + endif endif endif @@ -54,8 +56,20 @@ if (!isdir (init_path)) init_path = fileparts (init_path); endif - dirname = feval (funcname, init_path, dialog_name); + + if (__octave_link_enabled__ ()) + file_filter = cell (0, 2); + default_file_name = ""; + dialog_position = [240, 120]; + dialog_mode = "dir"; + [filename, dirname, filterindex] ... + = __octave_link_file_dialog__ (file_filter, dialog_name, + default_file_name, dialog_position, + dialog_mode, init_path); + else + dirname = feval (funcname, init_path, dialog_name); + endif endfunction diff --git a/scripts/startup/inputrc b/scripts/startup/inputrc --- a/scripts/startup/inputrc +++ b/scripts/startup/inputrc @@ -19,3 +19,8 @@ ## sequence for the DOWN arrow. "\e[B": history-search-forward + +## Disable so the usual paste shortcut will work on Windows systems. +## \C-q should still be available for quoted insert. + +"\C-v": "" diff --git a/test/for.tst b/test/for.tst --- a/test/for.tst +++ b/test/for.tst @@ -109,3 +109,11 @@ %! for i = cat (3, a, cellfun (@(x) 4 + x, a, "UniformOutput", 0)) %! assert (i, {1 + 2*j; 2 + 2*j++}) %! endfor + +%% test parsing of single-quoted character string appearing at the +%% beginning of a for loop +%!test +%! for i = 1:5 +%! 'foo'; +%! endfor +%! assert (i, 5); diff --git a/test/if.tst b/test/if.tst --- a/test/if.tst +++ b/test/if.tst @@ -85,3 +85,22 @@ %! end %! assert (__prog_output_assert__ ("pass")); +%% test parsing of single-quoted character string appearing at the +%% beginning of an if condition +%!test +%! if (1) +%! 'foo'; +%! x = 13; +%! endif +%! assert (x, 13); + +%% test parsing of single-quoted character string appearing at the +%% beginning of an if condition +%!test +%! if (0) +%! x = 42; +%! elseif (1) +%! 'foo'; +%! x = 13; +%! endif +%! assert (x, 13); diff --git a/test/switch.tst b/test/switch.tst --- a/test/switch.tst +++ b/test/switch.tst @@ -93,3 +93,12 @@ %% test/octave.test/switch/switch-6.m %!error eval ("switch 1 default 1; endswitch") +%% test parsing of single-quoted character string appearing immediately +%% after a switch case +%!test +%! switch (1) +%! case 1 +%! 'foo'; +%! x = 13; +%! endswitch +%! assert (x, 13); diff --git a/test/while.tst b/test/while.tst --- a/test/while.tst +++ b/test/while.tst @@ -68,3 +68,11 @@ %! __printf_assert__ ("\n"); %! assert (__prog_output_assert__ ("34")); +%% test parsing of single-quoted character string appearing immediately +%% after a while condition. +%!test +%! i = 0; +%! while (++i < 5) +%! 'foo'; +%! endwhile +%! assert (i, 5);