Mercurial > hg > octave-terminal
changeset 5567:80e629357483
[project @ 2005-12-07 06:31:28 by jwe]
author | jwe |
---|---|
date | Wed, 07 Dec 2005 06:31:28 +0000 |
parents | 2f5d0d8a7f13 |
children | e9cde940b271 |
files | scripts/ChangeLog scripts/audio/wavread.m scripts/audio/wavwrite.m src/ChangeLog src/error.cc src/error.h |
diffstat | 6 files changed, 680 insertions(+), 205 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,8 @@ +2005-12-06 John W. Eaton <jwe@octave.org> + + * audio/wavread.m, audio/wavwrite.m: Adapt to Octave coding style. + Avoid for loop in interleave/deinterleave steps. + 2005-12-06 Michael Zeising <michael@michaels-website.de> * audio/wavread.m, audio/wavwrite.m: New files.
--- a/scripts/audio/wavread.m +++ b/scripts/audio/wavread.m @@ -18,25 +18,24 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} {} @var{y} = wavread(@var{filename}) -## Load the RIFF/WAVE sound file @var{filename}, returning the samples in vector -## @var{y}. If the file contains multichannel data, then @var{y} is a matrix with the -## channels represented as columns. +## @deftypefn {Function File} {@var{y}} = wavread (@var{filename}) +## Load the RIFF/WAVE sound file @var{filename}, and return the samples +## in vector @var{y}. If the file contains multichannel data, then +## @var{y} is a matrix with the channels represented as columns. ## -## @deftypefnx {Function File} {} [@var{y},@var{Fs},@var{bits}] = wavread(@var{filename}) +## @deftypefnx {Function File} {[@var{y}, @var{Fs}, @var{bits}]} = wavread (@var{filename}) ## Additionally return the sample rate (@var{fs}) in Hz and the number of bits ## per sample (@var{bits}). ## -## @deftypefnx {Function File} {} [...] = wavread(@var{filename},@var{n}) +## @deftypefnx {Function File} {[@dots{}]} = wavread (@var{filename}, @var{n}) ## Read only the first @var{n} samples from each channel. ## -## @deftypefnx {Function File} {} [...] = wavread(@var{filename},[@var{n1} @var{n2}]) +## @deftypefnx {Function File} {[@dots{}]} = wavread(@var{filename},[@var{n1} @var{n2}]) ## Read only samples @var{n1} through @var{n2} from each channel. ## -## @deftypefnx {Function File} {} [@var{samples} @var{channels}] = wavread(@var{filename},'size') -## Return the number of samples (@var{n}) and channels (@var{ch}) instead of the -## audio data. -## +## @deftypefnx {Function File} {[@var{samples}, @var{channels}]} = wavread (@var{filename}, "size") +## Return the number of samples (@var{n}) and channels (@var{ch}) +## instead of the audio data. ## @end deftypefn ## ## @seealso{wavwrite} @@ -44,7 +43,8 @@ ## Author: Michael Zeising <michael.zeising@stud.uni-erlangen.de> ## Created: 06 December 2005 -function [y, samplesPerSec, bitsPerSample] = wavread (filename, param) +function [y, samples_per_sec, bits_per_sample] = wavread (filename, param) + FORMAT_PCM = 0x0001; # PCM (8/16/32 bit) FORMAT_IEEE_FLOAT = 0x0003; # IEEE float (32/64 bit) FORMAT_ALAW = 0x0006; # 8-bit ITU-T G.711 A-law (not yet supported) @@ -52,65 +52,83 @@ FORMAT_IMA_ADPCM = 0x0011; # IMA/ADPCM 4:1 compression (not yet supported) BYTEORDER = "ieee-le"; + if (nargin < 1 || nargin > 2) + usage ("wavread (filename, param)"); + endif + # open file for binary reading + + if (! ischar (filename)) + error ("wavwrite: expecting filename to be a character string"); + endif + [fid, msg] = fopen (filename, "rb"); if (fid < 0) error ("wavread: %s", msg) endif - # check for RIFF/WAVE header - ckID = char (fread (fid, 4))'; # chunk ID: "RIFF" + ## check for RIFF/WAVE header + ck_id = char (fread (fid, 4))'; fseek (fid, 4, SEEK_CUR); - WAVEID = char (fread (fid, 4))'; # WAVE ID: "WAVE" - if ((ckID ~= "RIFF") || (WAVEID ~= "WAVE")) + wave_id = char (fread (fid, 4))'; + if (ck_id != "RIFF" || wave_id != "WAVE") fclose (fid); error ("wavread: file contains no RIFF/WAVE signature"); endif - # find format chunk within the next 256 (4*64) bytes + ## find format chunk within the next 256 (4*64) bytes i = 1; - while 1 - if (char (fread (fid, 4))' == "fmt ") - break + while (true) + if (char (fread (fid, 4))' == "fmt "); + break; endif if (i++ == 64) fclose (fid); - error ("wavread: file contains no format chunk") + error ("wavread: file contains no format chunk"); endif endwhile - - ckSize = fread (fid, 1, "ulong", 0, BYTEORDER); # format chunk size - - formatTag = fread (fid, 1, "short", 0, BYTEORDER); # sample format code - if ((formatTag ~= FORMAT_PCM) && (formatTag ~= FORMAT_IEEE_FLOAT)) - fclose (fid); - error ("wavread: sample format %#x is not supported", formatTag) - endif + + ## format chunk size + ck_size = fread (fid, 1, "ulong", 0, BYTEORDER); - channels = fread (fid, 1, "short", 0, BYTEORDER); # number of interleaved channels - samplesPerSec = fread (fid, 1, "ulong", 0, BYTEORDER); # sample rate + ## sample format code + format_tag = fread (fid, 1, "short", 0, BYTEORDER); + if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT) + fclose (fid); + error ("wavread: sample format %#x is not supported", format_tag); + endif + + ## number of interleaved channels + channels = fread (fid, 1, "short", 0, BYTEORDER); + + ## sample rate + samples_per_sec = fread (fid, 1, "ulong", 0, BYTEORDER); + + ## bits per sample fseek (fid, 6, SEEK_CUR); - bitsPerSample = fread (fid, 1, "short", 0, BYTEORDER); # bits per sample - # ignore the rest of the chunk - fseek (fid, ckSize-16, SEEK_CUR); + bits_per_sample = fread (fid, 1, "short", 0, BYTEORDER); + + ## ignore the rest of the chunk + fseek (fid, ck_size-16, SEEK_CUR); - # find data chunk + ## find data chunk i = 1; - while 1 - if (char (fread(fid, 4))' == "data") - break + while (true) + if (char (fread (fid, 4))' == "data") + break; endif if (i++ == 64) fclose (fid); - error ("wavread: file contains no data chunk") + error ("wavread: file contains no data chunk"); endif end - - ckSize = fread (fid, 1, "ulong", 0, BYTEORDER); # data chunk size + + ## data chunk size + ck_size = fread (fid, 1, "ulong", 0, BYTEORDER); - # determine sample data type - if (formatTag == FORMAT_PCM) - switch bitsPerSample + ## determine sample data type + if (format_tag == FORMAT_PCM) + switch bits_per_sample case 8 format = "int8"; case 16 @@ -119,34 +137,37 @@ format = "int32"; otherwise fclose (fid); - error ("wavread: %d bits sample resolution is not supported with PCM", bitsPerSample); + error ("wavread: %d bits sample resolution is not supported with PCM", bits_per_sample); endswitch else - switch bitsPerSample + switch (bits_per_sample) case 32 format = "float32"; case 64 format = "float64"; otherwise fclose (fid); - error ("wavread: %d bits sample resolution is not supported with IEEE float", bitsPerSample); + error ("wavread: %d bits sample resolution is not supported with IEEE float", bits_per_sample); endswitch endif - # parse arguments - if (exist ("param","var") < 1) + ## parse arguments + if (nargin == 1) length = inf; else - if (size(param)(2) == 1) # number of samples is given + if (size (param, 2) == 1) + ## number of samples is given length = param * channels; - elseif (size(param)(2) == 2) # sample range is given - if fseek(fid, param(1) * channels * (bitsPerSample/8), SEEK_CUR) < 0 - warning ("wavread: seeking failed") + elseif (size (param, 2) == 2) + ## sample range is given + if (fseek (fid, param(1) * channels * (bits_per_sample/8), SEEK_CUR) < 0) + warning ("wavread: seeking failed"); endif length = (param(2)-param(1)) * channels; - elseif ((size (param)(2) == 4) && (char(param) == "size")) # size of the file is requested + elseif (size (param, 2) == 4 && char (param) == "size") + ## size of the file is requested fclose (fid); - y = [ckSize/channels/bitsPerSample/8 channels]; + y = [ck_size/channels/bits_per_sample/8, channels]; return else fclose (fid); @@ -154,25 +175,28 @@ endif endif - # read samples + ## read samples [yi, n] = fread (fid, length, format, 0, BYTEORDER); fclose (fid); - if (formatTag == FORMAT_PCM) - # normalize samples - switch bitsPerSample + if (format_tag == FORMAT_PCM) + ## normalize samples + switch (bits_per_sample) case 8 yi = (yi - 127)/127; # 8-bit samples are unsigned - case {16,32} - yi = yi/((2 ** bitsPerSample) / 2 - 1); + case {16, 32} + yi = yi/((2 ** bits_per_sample) / 2 - 1); endswitch endif - # deinterleave - y = []; - for (i = 1:channels) - y = [y yi(i:channels:n)]; - endfor + ## deinterleave + ## y = []; + ## for i = 1:channels + ## y = [y, yi(i:channels:n)]; + ## endfor + + nr = numel (yi) / channels; + y = reshape (yi, channels, nr)'; endfunction
--- a/scripts/audio/wavwrite.m +++ b/scripts/audio/wavwrite.m @@ -36,21 +36,27 @@ ## Author: Michael Zeising <michael.zeising@stud.uni-erlangen.de> ## Created: 06 December 2005 -function wavwrite (filename, y, samplesPerSec, bitsPerSample) +function wavwrite (filename, y, samples_per_sec, bits_per_sample) + BYTEORDER = "ieee-le"; - # parse arguments - if (exist ("samplesPerSec","var") < 1) - warning ("wavwrite: sample rate set to 8000 Hz") - samplesPerSec = 8000; + if (nargin < 2 || nargin > 4) + usage ("wavwrite (filename, y, samples_per_sec, bits_per_sample)"); endif - if (exist ("bitsPerSample","var") < 1) - warning ("wavwrite: sample resolution set to 16-bit") - bitsPerSample = 16; + + ## parse arguments + if (nargin < 3) + warning ("wavwrite: sample rate set to 8000 Hz"); + samples_per_sec = 8000; + endif + + if (nargin < 4) + warning ("wavwrite: sample resolution set to 16-bit"); + bits_per_sample = 16; endif - # determine sample format - switch bitsPerSample + ## determine sample format + switch (bits_per_sample) case 8 format = "int8"; case 16 @@ -58,57 +64,80 @@ case 32 format = "int32"; otherwise - fclose (fid); error ("wavread: sample resolution not supported"); endswitch - # calculate filesize + ## calculate filesize channels = size(y)(2); n = size(y)(1); + + ## size of data chunk + ck_size = n*channels*(bits_per_sample/8); - ckSize = n*channels*(bitsPerSample/8); # size of data chunk - - # open file for writing binary + ## open file for writing binary + + if (! ischar (filename)) + error ("wavwrite: expecting filename to be a character string"); + endif + [fid, msg] = fopen (filename, "wb"); if (fid < 0) error ("wavwrite: %s", msg) endif - # write RIFF/WAVE header + ## write RIFF/WAVE header c = 0; - c += fwrite (fid, "RIFF", "uchar"); - c += fwrite (fid, ckSize + 36, "ulong", 0, BYTEORDER); # file size - 8 - c += fwrite (fid, "WAVEfmt ", "uchar"); - c += fwrite (fid, 16, "ulong", 0, BYTEORDER); # size of fmt chunk - c += fwrite (fid, 0x0001, "short", 0, BYTEORDER); # sample format code (PCM) - c += fwrite (fid, channels, "short", 0, BYTEORDER); # channels - c += fwrite (fid, samplesPerSec, "ulong", 0, BYTEORDER); # sample rate - c += fwrite (fid, samplesPerSec*channels*bitsPerSample/8, "ulong", 0, BYTEORDER); # bytes per second - c += fwrite (fid, channels*bitsPerSample/8, "short", 0, BYTEORDER); # block align - c += fwrite (fid, bitsPerSample, "short", 0, BYTEORDER); # bits/sample - c += fwrite (fid, "data", "uchar"); - c += fwrite (fid, ckSize, "ulong", 0, BYTEORDER); # size of data chunk + c += fwrite (fid, "RIFF", "uchar"); + + ## file size - 8 + c += fwrite (fid, ck_size + 36, "ulong", 0, BYTEORDER); + c += fwrite (fid, "WAVEfmt ", "uchar"); + + ## size of fmt chunk + c += fwrite (fid, 16, "ulong", 0, BYTEORDER); + + ## sample format code (PCM) + c += fwrite (fid, 0x0001, "short", 0, BYTEORDER); + + ## channels + c += fwrite (fid, channels, "short", 0, BYTEORDER); + + ## sample rate + c += fwrite (fid, samples_per_sec, "ulong", 0, BYTEORDER); + + ## bytes per second + bps = samples_per_sec*channels*bits_per_sample/8; + c += fwrite (fid, bps, "ulong", 0, BYTEORDER); + + ## block align + c += fwrite (fid, channels*bits_per_sample/8, "short", 0, BYTEORDER); + + c += fwrite (fid, bits_per_sample, "short", 0, BYTEORDER); + c += fwrite (fid, "data", "uchar"); + c += fwrite (fid, ck_size, "ulong", 0, BYTEORDER); if (c < 25) fclose (fid); - error ("wavread: writing to file failed") + error ("wavread: writing to file failed"); endif - # scale samples - switch bitsPerSample + ## scale samples + switch (bits_per_sample) case 8 y = floor (y*127 + 127); - case {16,32} - y = floor (y*((2 ** bitsPerSample) / 2 - 1)); + case {16, 32} + y = floor (y*((2 ** bits_per_sample) / 2 - 1)); endswitch - # interleave samples - l = n*channels; - for (i = 1:channels) - yi(i:channels:l) = y(:,i); - endfor + ## interleave samples + ## l = n*channels; + ## for i = 1:channels + ## yi(i:channels:l) = y(:,i); + ## endfor + + yi = reshape (y', n*channels, 1); - # write to file + ## write to file c = fwrite (fid, yi, format, 0, BYTEORDER); fclose (fid);
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,25 @@ +2005-12-07 John W. Eaton <jwe@octave.org> + + * error.cc (Vbacktrace_on_warning, warning_options, + Vlast_warning_id, Vlast_error_id): New file-scope variables. + (Vwarning_frequency, Vwarning_option): Delete unused variables. + (set_warning_option): Delete unused function. + (Fwarning): Update for compatibility. Use DEFCMD, not DEFUN. + (warning_enabled, check_state): New functions. + (warning (const char *fmt, ...)): Use it. + (init_warning_options): New function. + (symbols_of_error): Call it. + (vwarning, Flastwarn): Handle Vlast_warning_id. Improve compatibility. + (handle_message): New arg, ID. Change all callers. + (vwarning, verror, error_1): New arg, ID. Change all callers. + (verror, Flasterr): Handle Vlast_error_id. Improve compatibility. + + * error.cc (message_with_id, usage_with_id, warning_with_id, + error_with_id, parse_error_with_id): New functions. + (error_2, warning_1, usage_1): New functions. + * error.h (message_with_id, usage_with_id, warning_with_id, + error_with_id, parse_error_with_id): Provide decls. + 2005-11-30 John W. Eaton <jwe@octave.org> * DLD-FUNCTIONS/schur.cc (Fschur): Doc string fix.
--- a/src/error.cc +++ b/src/error.cc @@ -37,6 +37,7 @@ #include "input.h" #include "pager.h" #include "oct-obj.h" +#include "oct-map.h" #include "utils.h" #include "ov.h" #include "ov-usr-fcn.h" @@ -59,19 +60,27 @@ // is encountered. static bool Vdebug_on_warning; +// TRUE means that Octave will try to display a stack trace when a +// warning is encountered. +static bool Vbacktrace_on_warning = false; + +// TRUE means that Octave will print a verbose warning. Currently unused. +static bool Vverbose_warning; + +// A structure containing (most of) the current state of warnings. +static Octave_map warning_options; + // The text of the last error message. static std::string Vlast_error_message; // The text of the last warning message. static std::string Vlast_warning_message; -// The warning frequency for Matlab handle graphics backwards -// compatibility warnings (currently not used). -static std::string Vwarning_frequency = "once"; +// The last warning message id. +static std::string Vlast_warning_id; -// The current warning state. Valid values are "on", "off", -// "backtrace", or "debug". -std::string Vwarning_option = "backtrace"; +// The last error message id. +static std::string Vlast_error_id; // Current error state. // @@ -116,10 +125,19 @@ discard_error_messages = false; } +static void +init_warning_options (const std::string& state = "on") +{ + warning_options.clear (); + + warning_options.assign ("identifier", "all"); + warning_options.assign ("state", state); +} + // Warning messages are never buffered. static void -vwarning (const char *name, const char *fmt, va_list args) +vwarning (const char *name, const char *id, const char *fmt, va_list args) { if (discard_warning_messages) return; @@ -146,6 +164,8 @@ if (! warning_state) { // This is the first warning in a possible series. + + Vlast_warning_id = id; Vlast_warning_message = msg_string; } @@ -156,7 +176,7 @@ static void verror (bool save_last_error, std::ostream& os, - const char *name, const char *fmt, va_list args) + const char *name, const char *id, const char *fmt, va_list args) { if (discard_error_messages) return; @@ -189,6 +209,8 @@ if (! error_state && save_last_error) { // This is the first error in a possible series. + + Vlast_error_id = id; Vlast_error_message = msg_string; } @@ -227,7 +249,8 @@ // just set the error state. static void -error_1 (std::ostream& os, const char *name, const char *fmt, va_list args) +error_1 (std::ostream& os, const char *name, const char *id, + const char *fmt, va_list args) { if (error_state != -2) { @@ -242,14 +265,14 @@ { char *tmp_fmt = strsave (fmt); tmp_fmt[len - 1] = '\0'; - verror (true, os, name, tmp_fmt, args); + verror (true, os, name, id, tmp_fmt, args); delete [] tmp_fmt; } error_state = -2; } else - verror (true, os, name, fmt, args); + verror (true, os, name, id, fmt, args); } } else @@ -265,17 +288,41 @@ { va_list args; va_start (args, fmt); - verror (false, std::cerr, name, fmt, args); + verror (false, std::cerr, name, "", fmt, args); va_end (args); } void +message_with_id (const char *name, const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + verror (false, std::cerr, name, id, fmt, args); + va_end (args); +} + +void +usage_1 (const char *id, const char *fmt, va_list args) +{ + verror (true, std::cerr, "usage", id, fmt, args); + error_state = -1; +} + +void usage (const char *fmt, ...) { va_list args; va_start (args, fmt); - verror (true, std::cerr, "usage", fmt, args); - error_state = -1; + usage_1 ("", fmt, args); + va_end (args); +} + +void +usage_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + usage_1 (id, fmt, args); va_end (args); } @@ -293,12 +340,12 @@ { char *tmp_fmt = strsave (fmt); tmp_fmt[len - 1] = '\0'; - verror (false, std::cerr, 0, tmp_fmt, args); + verror (false, std::cerr, 0, "", tmp_fmt, args); delete [] tmp_fmt; } } else - verror (false, std::cerr, 0, fmt, args); + verror (false, std::cerr, 0, "", fmt, args); } } else @@ -387,21 +434,113 @@ } } -void -warning (const char *fmt, ...) +static int +check_state (const std::string& state) +{ + // -1: not found + // 0: found, "off" + // 1: found, "on" + // 2: found, "error" + + if (state == "off") + return 0; + else if (state == "on") + return 1; + else if (state == "error") + return 2; + else + return -1; +} + +// For given warning ID, return 0 if warnings are disabled, 1 if +// enabled, and 2 if this ID should be an error instead of a warning. + +static int +warning_enabled (const std::string& id) { - if (Vwarning_option != "off") + int retval = 0; + + int all_state = -1; + int id_state = -1; + + octave_idx_type nel = warning_options.numel (); + + if (nel > 0) + { + Cell identifier = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + bool all_found = false; + bool id_found = false; + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value ov = identifier(i); + std::string ovs = ov.string_value (); + + if (! all_found && ovs == "all") + { + all_state = check_state (state(i).string_value ()); + + if (all_state >= 0) + all_found = true; + } + + if (! id_found && ovs == id) + { + id_state = check_state (state(i).string_value ()); + + if (id_state >= 0) + id_found = true; + } + + if (all_found && id_found) + break; + } + + } + + if (all_state == -1) + panic_impossible (); + + if (all_state == 0) + { + if (id_state >= 0) + retval = id_state; + } + else if (all_state == 1) + { + if (id_state == 0 || id_state == 2) + retval = id_state; + else + retval = all_state; + } + else if (all_state == 2) + retval = 2; + + return retval; +} + +static void +warning_1 (const char *id, const char *fmt, va_list args) +{ + int warn_opt = warning_enabled (id); + + if (warn_opt == 2) + { + // Handle this warning as an error. + + error (id, fmt, args); + } + else if (warn_opt == 1) { if (curr_sym_tab != top_level_sym_tab - && Vwarning_option == "backtrace" + && Vbacktrace_on_warning && ! warning_state && ! discard_warning_messages) pr_where ("warning", false); - va_list args; - va_start (args, fmt); - vwarning ("warning", fmt, args); - va_end (args); + vwarning ("warning", id, fmt, args); warning_state = 1; @@ -419,14 +558,29 @@ } void -error (const char *fmt, ...) +warning (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + warning_1 ("", fmt, args); + va_end (args); +} + +void +warning_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + warning_1 (id, fmt, args); + va_end (args); +} + +static void +error_2 (const char *id, const char *fmt, va_list args) { int init_state = error_state; - va_list args; - va_start (args, fmt); - error_1 (std::cerr, "error", fmt, args); - va_end (args); + error_1 (std::cerr, "error", id, fmt, args); if ((interactive || forced_interactive) && Vdebug_on_error && init_state == 0 && curr_function) @@ -445,11 +599,38 @@ } void +error (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + error_2 ("", fmt, args); + va_end (args); +} + +void +error_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + error_2 (id, fmt, args); + va_end (args); +} + +void parse_error (const char *fmt, ...) { va_list args; va_start (args, fmt); - error_1 (std::cerr, 0, fmt, args); + error_1 (std::cerr, 0, "", fmt, args); + va_end (args); +} + +void +parse_error_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + error_1 (std::cerr, 0, id, fmt, args); va_end (args); } @@ -460,7 +641,7 @@ va_start (args, fmt); buffer_error_messages = 0; discard_error_messages = false; - verror (false, std::cerr, "panic", fmt, args); + verror (false, std::cerr, "panic", "", fmt, args); va_end (args); abort (); } @@ -470,7 +651,7 @@ { va_list args; va_start (args, fmt); - error_1 (octave_stdout, 0, fmt, args); + error_1 (octave_stdout, 0, "", fmt, args); va_end (args); } @@ -480,12 +661,13 @@ defun_usage_message_1 ("%s", msg.c_str ()); } -typedef void (*error_fun)(const char *, ...); +typedef void (*error_fun)(const char *, const char *, ...); extern octave_value_list Fsprintf (const octave_value_list&, int); static std::string -handle_message (error_fun f, const char *msg, const octave_value_list& args) +handle_message (error_fun f, const char *id, const char *msg, + const octave_value_list& args) { std::string retval; @@ -529,14 +711,14 @@ { char *tmp_msg = strsave (msg); tmp_msg[len - 1] = '\0'; - f ("%s\n", tmp_msg); + f (id, "%s\n", tmp_msg); retval = tmp_msg; delete [] tmp_msg; } } else { - f ("%s", msg); + f (id, "%s", msg); retval = msg; } @@ -599,33 +781,15 @@ @end example\n\ @end deftypefn") { + // XXX FIXME XXX -- need to extract and pass message id to + // handle_message. + octave_value_list retval; - handle_message (error, "unspecified error", args); + handle_message (error_with_id, "", "unspecified error", args); return retval; } -static inline octave_value_list -set_warning_option (const std::string& state, - const std::string& frequency, int nargout) -{ - octave_value_list retval; - - if (nargout > 1) - retval(1) = Vwarning_frequency; - - if (nargout >= 0) - retval(0) = Vwarning_option; - - if (! state.empty ()) - Vwarning_option = state; - - if (! frequency.empty ()) - Vwarning_frequency = frequency; - - return retval; -} - -DEFUN (warning, args, nargout, +DEFCMD (warning, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} warning (@var{msg})\n\ Print a warning message @var{msg} prefixed by the string @samp{warning: }. \n\ @@ -635,84 +799,279 @@ to go on.\n\ @end deftypefn") { - octave_value_list retval; + octave_value retval; - int argc = args.length () + 1; + int nargin = args.length (); + int argc = nargin + 1; bool done = false; - if (args.all_strings_p ()) + if (argc > 1 && args.all_strings_p ()) { string_vector argv = args.make_argv ("warning"); if (! error_state) { - if (argc == 1) + std::string arg1 = argv(1); + std::string arg2 = "all"; + + if (argc == 3) + arg2 = argv(2); + + if (arg1 == "on" || arg1 == "off" || arg1 == "error") { - retval = set_warning_option ("", "", nargout); - done = true; - } - else if (argc == 2) - { - std::string arg = argv(1); + Octave_map old_warning_options = warning_options; + + if (arg2 == "all") + { + Octave_map tmp; - if (arg == "on" || arg == "off" || arg == "backtrace") - { - retval = set_warning_option (arg, "", nargout); + tmp.assign ("identifier", arg2); + tmp.assign ("state", arg1); + + warning_options = tmp; + done = true; } - else if (arg == "once" || arg == "always") + else if (arg2 == "backtrace") + { + if (arg1 != "error") + { + Vbacktrace_on_warning = (arg1 == "on"); + done = true; + } + } + else if (arg2 == "debug") + { + if (arg1 != "error") + { + bind_builtin_variable ("debug_on_warning", arg1 == "on"); + done = true; + } + } + else if (arg2 == "verbose") + { + if (arg1 != "error") + { + Vverbose_warning = (arg1 == "on"); + done = true; + } + } + else { - retval = set_warning_option ("", arg, nargout); + if (arg2 == "last") + arg2 = Vlast_warning_id; + + if (arg2 == "all") + init_warning_options (arg1); + else + { + Cell ident = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + octave_idx_type nel = ident.numel (); + + bool found = false; + + for (octave_idx_type i = 0; i < nel; i++) + { + if (ident(i).string_value () == arg2) + { + // XXX FIXME XXX -- if state for "all" is + // same as arg1, we can simply remove the + // item from the list. + + state(i) = arg1; + warning_options.assign ("state", state); + found = true; + break; + } + } + + if (! found) + { + // XXX FIXME XXX -- if state for "all" is + // same as arg1, we don't need to do anything. + + ident.resize (dim_vector (1, nel+1)); + state.resize (dim_vector (1, nel+1)); + + ident(nel) = arg2; + state(nel) = arg1; + + warning_options.clear (); + + warning_options.assign ("identifier", ident); + warning_options.assign ("state", state); + } + } + done = true; } - else if (arg == "debug") + + if (done && nargout > 0) + retval = warning_options; + } + else if (arg1 == "query") + { + if (arg2 == "all") + retval = warning_options; + else if (arg2 == "backtrace" || arg2 == "debug" + || arg2 == "verbose") + { + Octave_map tmp; + tmp.assign ("identifier", arg2); + if (arg2 == "backtrace") + tmp.assign ("state", Vbacktrace_on_warning ? "on" : "off"); + else if (arg2 == "debug") + tmp.assign ("state", Vdebug_on_warning ? "on" : "off"); + else + tmp.assign ("state", Vverbose_warning ? "on" : "off"); + } + else { - bind_builtin_variable ("debug_on_warning", true); - retval = set_warning_option ("", "", nargout); - done = true; + if (arg2 == "last") + arg2 = Vlast_warning_id; + + Cell ident = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + octave_idx_type nel = ident.numel (); + + bool found = false; + + std::string val; + + for (octave_idx_type i = 0; i < nel; i++) + { + if (ident(i).string_value () == arg2) + { + val = state(i).string_value (); + found = true; + break; + } + } + + if (found) + { + Octave_map tmp; + + tmp.assign ("identifier", arg2); + tmp.assign ("state", val); + + retval = tmp; + } + else + error ("warning: invalid warning tag `%s'", arg2.c_str ()); } + + done = true; } } } + else if (argc == 1) + { + retval = warning_options; - if (! done) + done = true; + } + else if (argc == 2) + { + octave_value arg = args(0); + + Octave_map old_warning_options = warning_options; + + if (arg.is_map ()) + { + Octave_map m = arg.map_value (); + + if (m.contains ("identifier") && m.contains ("state")) + warning ("warning: setting state with structure not implemented"); + else + error ("warning: expecting structure with fields `identifier' and `state'"); + + done = true; + + if (nargout > 0) + retval = old_warning_options; + } + } + + if (! (error_state || done)) { + octave_value_list nargs = args; + + std::string id; + + if (nargin > 1) + { + std::string arg1 = args(0).string_value (); + + if (! error_state) + { + if (arg1.find ('%') == NPOS) + { + id = arg1; + + nargs.resize (nargin-1); + + for (int i = 1; i < nargin; i++) + nargs(i-1) = args(i); + } + } + else + return retval; + } + + // handle_message. + std::string prev_msg = Vlast_warning_message; - std::string curr_msg - = handle_message (warning, "unspecified warning", args); + std::string curr_msg = handle_message (warning_with_id, id.c_str (), + "unspecified warning", nargs); if (nargout > 0) - retval(0) = Vlast_warning_message; + retval = prev_msg; } return retval; } -DEFUN (lasterr, args, , +DEFUN (lasterr, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} lasterr ()\n\ -@deftypefnx {Built-in Function} {} lasterr (@var{msg})\n\ +@deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lasterr (@var{msg}, @var{msgid})\n\ Without any arguments, return the last error message. With one\n\ -argument, set the last error message to @var{msg}.\n\ +argument, set the last error message to @var{msg}. With two arguments,\n\ +also set the last message identifier.\n\ @end deftypefn") { octave_value_list retval; int argc = args.length () + 1; - if (argc == 1 || argc == 2) + if (argc < 4) { string_vector argv = args.make_argv ("lasterr"); if (! error_state) { - if (argc == 1) - retval(0) = Vlast_error_message; - else + std::string prev_error_id = Vlast_error_id; + std::string prev_error_message = Vlast_error_message; + + if (argc > 2) + Vlast_error_id = argv(2); + + if (argc > 1) Vlast_error_message = argv(1); + + if (argc == 1 || nargout > 0) + { + retval(1) = prev_error_id; + retval(0) = prev_error_message; + } } + else + error ("lastwarn: expecting arguments to be character strings"); } else print_usage ("lasterr"); @@ -724,24 +1083,42 @@ DEFALIAS (error_text, lasterr); DEFALIAS (__error_text__, lasterr); -DEFUN (lastwarn, args, , +DEFUN (lastwarn, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} lastwarn ()\n\ -@deftypefnx {Built-in Function} {} lastwarn (@var{msg})\n\ +@deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lastwarn (@var{msg}, @var{msgid})\n\ Without any arguments, return the last warning message. With one\n\ -argument, set the last warning message to @var{msg}.\n\ +argument, set the last warning message to @var{msg}. With two arguments,\n\ +also set the last message identifier.\n\ @end deftypefn") { octave_value_list retval; int argc = args.length () + 1; - string_vector argv = args.make_argv ("lastwarn"); + if (argc < 4) + { + string_vector argv = args.make_argv ("lastwarn"); + + if (! error_state) + { + std::string prev_warning_id = Vlast_warning_id; + std::string prev_warning_message = Vlast_warning_message; + + if (argc > 2) + Vlast_warning_id = argv(2); - if (argc == 1) - retval(0) = Vlast_warning_message; - else if (argc == 2) - Vlast_warning_message = argv(1); + if (argc > 1) + Vlast_warning_message = argv(1); + + if (argc == 1 || nargout > 0) + { + retval(1) = prev_warning_id; + retval(0) = prev_warning_message; + } + } + else + error ("lastwarn: expecting arguments to be character strings"); + } else print_usage ("lastwarn"); @@ -778,7 +1155,7 @@ @end deftypefn") { octave_value_list retval; - handle_message (usage, "unknown", args); + handle_message (usage_with_id, "", "unknown", args); return retval; } @@ -809,6 +1186,8 @@ void symbols_of_error (void) { + init_warning_options (); + DEFVAR (beep_on_error, false, beep_on_error, "-*- texinfo -*-\n\ @defvr {Built-in Variable} beep_on_error\n\
--- a/src/error.h +++ b/src/error.h @@ -37,6 +37,22 @@ extern void warning (const char *fmt, ...); extern void error (const char *fmt, ...); extern void parse_error (const char *fmt, ...); + +extern void +message_with_id (const char *id, const char *name, const char *fmt, ...); + +extern void +usage_with_id (const char *id, const char *fmt, ...); + +extern void +warning_with_id (const char *id, const char *fmt, ...); + +extern void +error_with_id (const char *id, const char *fmt, ...); + +extern void +parse_error_with_id (const char *id, const char *fmt, ...); + extern void panic (const char *fmt, ...) GCC_ATTR_NORETURN; // Helper function for print_usage defined in defun.cc.