Mercurial > hg > octave-lojdl
diff src/utils.cc @ 1:78fd87e624cb
[project @ 1993-08-08 01:13:40 by jwe]
Initial revision
author | jwe |
---|---|
date | Sun, 08 Aug 1993 01:13:40 +0000 |
parents | |
children | a2db6687354d |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/src/utils.cc @@ -0,0 +1,1274 @@ +// utils.cc -*- C++ -*- +/* + +Copyright (C) 1992, 1993 John W. Eaton + +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 2, 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, write to the Free +Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* + +The 11 functions listed below were adapted from a similar functions +from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991 +Free Software Foundation, Inc. + + polite_directory_format absolute_pathname + absolute_program base_pathname + read_octal sub_append_string + decode_prompt_string pathname_backup + make_absolute get_working_directory + change_to_directory + +*/ + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/param.h> +#include <setjmp.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <math.h> +#include <limits.h> +#include <iostream.h> +#include <strstream.h> +#include <fstream.h> +#include <dirent.h> + +#define NLENGTH(dirent) (strlen((dirent)->d_name)) + +#ifdef HAVE_TERMIO_H +#include <termio.h> +#else +#ifdef HAVE_SGTTY_H +#include <sgtty.h> +#else +LOSE! LOSE! +#endif +#endif + +extern "C" +{ + extern int ioctl (int, int, ...); + char *tilde_expand (char *s); /* From readline's tilde.c */ +} + +#include "SLStack.h" + +#include "statdefs.h" +#include "procstream.h" +#include "user-prefs.h" +#include "variables.h" +#include "error.h" +#include "utils.h" +#include "octave.h" +#include "mappers.h" +#include "version.h" +#include "tree-const.h" +#include "unwind-prot.h" +#include "octave-hist.h" + +// Top level context (?) +extern jmp_buf toplevel; + +// Pipe to gnuplot. +static oprocstream plot_stream; + +// Non-zero means follow symbolic links that point to directories just +// as if they are real directories. +static int follow_symbolic_links = 1; + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +// The size that strings change by. +#ifndef DEFAULT_ARRAY_SIZE +#define DEFAULT_ARRAY_SIZE 512 +#endif + +// The growth rate for the prompt string. +#ifndef PROMPT_GROWTH +#define PROMPT_GROWTH 50 +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +// Where to find the site-wide configuration file +#ifndef OCTAVE_HOME +#define OCTAVE_HOME "/usr/local" +#endif + +// Temp storage for a path. +static char tdir[MAXPATHLEN]; + +// List of files to delete when we exit or crash. +static SLStack <char *> tmp_files; + +/* + * Save a string. + */ +char * +strsave (const char *s) +{ + if (s == (char *) NULL) + return (char *) NULL; + + int len = strlen (s); + char *tmp = new char [len+1]; + tmp = strcpy (tmp, s); + return tmp; +} + +/* + * Concatenate two strings. + */ +char * +strconcat (const char *s, const char *t) +{ + int len = strlen (s) + strlen (t); + char *tmp = new char [len+1]; + strcpy (tmp, s); + return strcat (tmp, t); +} + +/* + * Throw away input until a given character is read. + */ +void +discard_until (istream& stream, char character) +{ + int c; + for (;;) + { + stream >> c; + if (c == EOF || c == character) + break; + } + if (c != EOF) + stream.putback ((char) c); +} + +void +check_dimensions (int& nr, int& nc, char *warnfor) +{ + if (nr < 0 || nc < 0) + { + if (user_pref.treat_neg_dim_as_zero) + nr = nc = 0; + else + { + message (warnfor, "can't create a matrix with negative dimensions"); + jump_to_top_level (); + } + } +} + +/* + * Set terminal in raw mode. From less-177. + * + * Change terminal to "raw mode", or restore to "normal" mode. + * "Raw mode" means + * 1. An outstanding read will complete on receipt of a single keystroke. + * 2. Input is not echoed. + * 3. On output, \n is mapped to \r\n. + * 4. \t is NOT expanded into spaces. + * 5. Signal-causing characters such as ctrl-C (interrupt), + * etc. are NOT disabled. + * It doesn't matter whether an input \n is mapped to \r, or vice versa. + */ +void +raw_mode (int on) +{ + static int curr_on = 0; + +// HACK! HACK! + + int tty_fd = 1; + + if (on == curr_on) + return; + +#ifdef HAVE_TERMIO_H + { + struct termio s; + static struct termio save_term; + + if (on) + { +// Get terminal modes. + + ioctl(tty_fd, TCGETA, &s); + +// Save modes and set certain variables dependent on modes. + + save_term = s; +// ospeed = s.c_cflag & CBAUD; +// erase_char = s.c_cc[VERASE]; +// kill_char = s.c_cc[VKILL]; + +// Set the modes to the way we want them. + + s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); + s.c_oflag |= (OPOST|ONLCR|TAB3); + s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); + s.c_cc[VMIN] = 1; + s.c_cc[VTIME] = 0; + } + else + { +// Restore saved modes. + s = save_term; + } + ioctl(tty_fd, TCSETAW, &s); + } +#else +#ifdef HAVE_SGTTY_H + { + struct sgttyb s; + static struct sgttyb save_term; + + if (on) + { +// Get terminal modes. + + ioctl(tty_fd, TIOCGETP, &s); + +// Save modes and set certain variables dependent on modes. + + save_term = s; +// ospeed = s.sg_ospeed; +// erase_char = s.sg_erase; +// kill_char = s.sg_kill; + +// Set the modes to the way we want them. + + s.sg_flags |= CBREAK; + s.sg_flags &= ~(ECHO|XTABS); + } + else + { +// Restore saved modes. + s = save_term; + } + ioctl(tty_fd, TIOCSETN, &s); + } +#else +LOSE! LOSE! +#endif +#endif + + curr_on = on; +} + +/* + * Read one character from the terminal. + */ +int +kbhit (void) +{ + int c; + raw_mode (1); + c = cin.get (); + raw_mode (0); + return c; +} + +char ** +pathstring_to_vector (char *pathstring) +{ + static char **path = (char **) NULL; + + if (pathstring != (char *) NULL) + { + int nelem = 0; + pathstring = strsave (pathstring); + if (*pathstring != '\0') + { + nelem++; + char *ptr = pathstring; + while (*ptr != '\0') + { + if (*ptr == ':') + nelem++; + ptr++; + } + } + + delete [] path; + path = new char * [nelem+1]; + path[nelem] = (char *) NULL; + + int i = 0; + char *ptr = pathstring; + while (i < nelem) + { + char *end = strchr (ptr, ':'); + if (end != (char *) NULL) + *end = '\0'; + char *result = tilde_expand (ptr); + path[i] = strsave (result); + free (result); + ptr = end + 1; + i++; + } + + delete [] pathstring; + } + + return path; +} + +static char * +octave_home (void) +{ + static char *home = (char *) NULL; + delete [] home; + char *oh = getenv ("OCTAVE_HOME"); + if (oh != (char *) NULL) + home = strsave (oh); + else + home = strsave (OCTAVE_HOME); + return home; +} + +static char * +octave_lib_dir (void) +{ + static char *ol = (char *) NULL; + delete [] ol; + char *oh = octave_home (); + char *tmp = strconcat (oh, "/lib/octave/"); + ol = strconcat (tmp, version_string); + return ol; +} + +char * +default_path (void) +{ + static char *pathstring = (char *) NULL; + delete [] pathstring; + char *oct_path = getenv ("OCTAVE_PATH"); + if (oct_path != (char *) NULL) + pathstring = strsave (oct_path); + else + { + char *libdir = octave_lib_dir (); + pathstring = strconcat (".:", libdir); + } + return pathstring; +} + +char * +get_site_defaults (void) +{ + static char *sd = (char *) NULL; + delete [] sd; + char *libdir = octave_lib_dir (); + sd = strconcat (libdir, "/octaverc"); + return sd; +} + +char * +default_pager (void) +{ + static char *pager_binary = (char *) NULL; + delete [] pager_binary; + char *pgr = getenv ("PAGER"); + if (pgr != (char *) NULL) + pager_binary = strsave (pgr); + else +#ifdef DEFAULT_PAGER + pager_binary = strsave (DEFAULT_PAGER); +#else + pager_binary = strsave (""); +#endif + + return pager_binary; +} + +/* + * See if the given file is in the path. + */ +char * +file_in_path (char *name, char *suffix) +{ + char *nm = strconcat ("/", name); + char *tmp = nm; + if (suffix != (char *) NULL) + { + nm = strconcat (tmp, suffix); + delete [] tmp; + } + + if (!the_current_working_directory) + get_working_directory ("file_in_path"); + + char **path = pathstring_to_vector (user_pref.loadpath); + + char **ptr = path; + if (ptr != (char **) NULL) + { + while (*ptr != (char *) NULL) + { + char *tmp_p = strconcat (*ptr, nm); + char *p = make_absolute (tmp_p, the_current_working_directory); + delete [] tmp_p; + ifstream in_file (p); + if (in_file) + { + in_file.close (); + delete [] nm; + return p; + } + delete [] p; + ptr++; + } + } + + delete [] nm; + return (char *) NULL; +} + +/* + * See if there is an M-file in the path. If so, return the full path + * to the file. + */ +char * +m_file_in_path (char *name) +{ + return file_in_path (name, ".m"); +} + +/* + * Return a pretty pathname. If the first part of the pathname is the + * same as $HOME, then replace that with `~'. + */ +char * +polite_directory_format (char *name) +{ + int l = home_directory ? strlen (home_directory) : 0; + + if (l > 1 && strncmp (home_directory, name, l) == 0 + && (!name[l] || name[l] == '/')) + { + strcpy (tdir + 1, name + l); + tdir[0] = '~'; + return (tdir); + } + else + return name; +} + +/* + * Return 1 if STRING contains an absolute pathname, else 0. + */ +int +absolute_pathname (char *string) +{ + if (!string || !*string) + return 0; + + if (*string == '/') + return 1; + + if (*string++ == '.') + { + if ((!*string) || *string == '/') + return 1; + + if (*string++ == '.') + if (!*string || *string == '/') + return 1; + } + return 0; +} + +/* + * Return 1 if STRING is an absolute program name; it is absolute if + * it contains any slashes. This is used to decide whether or not to + * look up through $PATH. + */ +int +absolute_program (char *string) +{ + return (strchr (string, '/') != (char *)NULL); +} + +/* + * Return the `basename' of the pathname in STRING (the stuff after + * the last '/'). If STRING is not a full pathname, simply return it. + */ +char * +base_pathname (char *string) +{ + char *p = strrchr (string, '/'); + + if (!absolute_pathname (string)) + return (string); + + if (p) + return (++p); + else + return (string); +} + +/* + * Return the octal number parsed from STRING, or -1 to indicate that + * the string contained a bad number. + */ +int +read_octal (char *string) +{ + int result = 0; + int digits = 0; + + while (*string && *string >= '0' && *string < '8') + { + digits++; + result = (result * 8) + *string++ - '0'; + } + + if (!digits || result > 0777 || *string) + result = -1; + + return result; +} + +/* + * Append SOURCE to TARGET at INDEX. SIZE is the current amount of + * space allocated to TARGET. SOURCE can be NULL, in which case + * nothing happens. Gets rid of SOURCE by free ()ing it. Returns + * TARGET in case the location has changed. + */ +char * +sub_append_string (char *source, char *target, int *index, int *size) +{ + if (source) + { + while ((int)strlen (source) >= (int)(*size - *index)) + { + char *tmp = new char [*size += DEFAULT_ARRAY_SIZE]; + strcpy (tmp, target); + delete [] target; + target = tmp; + } + + strcat (target, source); + *index += strlen (source); + + delete [] source; + } + return target; +} + +/* + * Return a string which will be printed as a prompt. The string may + * contain special characters which are decoded as follows: + * + * \t the time + * \d the date + * \n CRLF + * \s the name of the shell (program) + * \w the current working directory + * \W the last element of PWD + * \u your username + * \h the hostname + * \# the command number of this command + * \! the history number of this command + * \$ a $ or a # if you are root + * \<octal> character code in octal + * \\ a backslash + */ +char * +decode_prompt_string (char *string) +{ + int result_size = PROMPT_GROWTH; + int result_index = 0; + char *result = new char [PROMPT_GROWTH]; + int c; + char *temp = (char *)NULL; + + result[0] = 0; + while (c = *string++) + { + if (c == '\\') + { + c = *string; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + char octal_string[4]; + int n; + + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; + + n = read_octal (octal_string); + + temp = strsave ("\\"); + if (n != -1) + { + string += 3; + temp[0] = n; + } + + c = 0; + goto add_string; + } + + case 't': + case 'd': + /* Make the current time/date into a string. */ + { + long the_time = time (0); + char *ttemp = ctime (&the_time); + temp = strsave (ttemp); + + if (c == 't') + { + strcpy (temp, temp + 11); + temp[8] = '\0'; + } + else + temp[10] = '\0'; + + goto add_string; + } + + case 'n': + if (!no_line_editing) + temp = strsave ("\r\n"); + else + temp = strsave ("\n"); + goto add_string; + + case 's': + { + temp = base_pathname (prog_name); + temp = strsave (temp); + goto add_string; + } + + case 'w': + case 'W': + { + char t_string[MAXPATHLEN]; +#define EFFICIENT +#ifdef EFFICIENT + +// Use the value of PWD because it is much more effecient. + + temp = user_pref.pwd; + + if (!temp) + getcwd (t_string, MAXPATHLEN); + else + strcpy (t_string, temp); +#else + getcwd (t_string, MAXPATHLEN); +#endif /* EFFICIENT */ + + if (c == 'W') + { + char *dir = strrchr (t_string, '/'); + if (dir && dir != t_string) + strcpy (t_string, dir + 1); + temp = strsave (t_string); + } + else + temp = strsave (polite_directory_format (t_string)); + goto add_string; + } + + case 'u': + { + temp = strsave (user_name); + + goto add_string; + } + + case 'h': + { + char *t_string; + + temp = strsave (host_name); + if (t_string = strchr (temp, '.')) + *t_string = '\0'; + + goto add_string; + } + + case '#': + { + char number_buffer[20]; + sprintf (number_buffer, "%d", current_command_number); + temp = strsave (number_buffer); + goto add_string; + } + + case '!': + { + char number_buffer[20]; + int num = current_history_number (); + if (num > 0) + sprintf (number_buffer, "%d", num); + else + strcpy (number_buffer, "!"); + temp = strsave (number_buffer); + goto add_string; + } + + case '$': + temp = strsave (geteuid () == 0 ? "#" : "$"); + goto add_string; + + case '\\': + temp = strsave ("\\"); + goto add_string; + + default: + temp = strsave ("\\ "); + temp[1] = c; + + add_string: + if (c) + string++; + result = + (char *)sub_append_string (temp, result, + &result_index, &result_size); + temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */ + result[result_index] = '\0'; + break; + } + } + else + { + while (3 + result_index > result_size) + { + char *tmp = new char [result_size += PROMPT_GROWTH]; + strcpy (tmp, result); + delete [] result; + result = tmp; + } + result[result_index++] = c; + result[result_index] = '\0'; + } + } + +#if 0 + /* I don't really think that this is a good idea. Do you? */ + if (!find_variable ("NO_PROMPT_VARS")) + { + WORD_LIST *expand_string (), *list; + char *string_list (); + + list = expand_string (result, 1); + free (result); + result = string_list (list); + dispose_words (list); + } +#endif + + return result; +} + +/* + * Remove the last N directories from PATH. Do not PATH blank. + * PATH must contain enoung space for MAXPATHLEN characters. + */ +void +pathname_backup (char *path, int n) +{ + register char *p; + + if (!*path) + return; + + p = path + (strlen (path) - 1); + + while (n--) + { + while (*p == '/' && p != path) + p--; + + while (*p != '/' && p != path) + p--; + + *++p = '\0'; + } +} + +/* + * Turn STRING (a pathname) into an absolute pathname, assuming that + * DOT_PATH contains the symbolic location of '.'. This always + * returns a new string, even if STRING was an absolute pathname to + * begin with. + */ +char * +make_absolute (char *string, char *dot_path) +{ + static char current_path[MAXPATHLEN]; + register char *cp; + + if (!dot_path || *string == '/') + return strsave (string); + + strcpy (current_path, dot_path); + + if (!current_path[0]) + strcpy (current_path, "./"); + + cp = current_path + (strlen (current_path) - 1); + + if (*cp++ != '/') + *cp++ = '/'; + + *cp = '\0'; + + while (*string) + { + if (*string == '.') + { + if (!string[1]) + return strsave (current_path); + + if (string[1] == '/') + { + string += 2; + continue; + } + + if (string[1] == '.' && (string[2] == '/' || !string[2])) + { + string += 2; + + if (*string) + string++; + + pathname_backup (current_path, 1); + cp = current_path + strlen (current_path); + continue; + } + } + + while (*string && *string != '/') + *cp++ = *string++; + + if (*string) + *cp++ = *string++; + + *cp = '\0'; + } + return strsave (current_path); +} + +/* + * Return a consed string which is the current working directory. + * FOR_WHOM is the name of the caller for error printing. + */ +char * +get_working_directory (char *for_whom) +{ + if (!follow_symbolic_links) + { + if (the_current_working_directory) + delete [] the_current_working_directory; + + the_current_working_directory = (char *)NULL; + } + + if (!the_current_working_directory) + { + char *directory; + + the_current_working_directory = new char [MAXPATHLEN]; + directory = getcwd (the_current_working_directory, MAXPATHLEN); + if (!directory) + { + message (for_whom, the_current_working_directory); + delete [] the_current_working_directory; + the_current_working_directory = (char *)NULL; + return (char *)NULL; + } + } + + return the_current_working_directory; +} + +/* + * Do the work of changing to the directory NEWDIR. Handle symbolic + * link following, etc. + */ +int +change_to_directory (char *newdir) +{ + char *t; + + if (follow_symbolic_links) + { + if (!the_current_working_directory) + get_working_directory ("cd_links"); + + if (the_current_working_directory) + t = make_absolute (newdir, the_current_working_directory); + else + t = strsave (newdir); + + /* Get rid of trailing `/'. */ + { + register int len_t = strlen (t); + if (len_t > 1) + { + --len_t; + if (t[len_t] == '/') + t[len_t] = '\0'; + } + } + + if (chdir (t) < 0) + { + delete [] t; + return 0; + } + + if (the_current_working_directory) + strcpy (the_current_working_directory, t); + + delete [] t; + return 1; + } + else + { + if (chdir (newdir) < 0) + return 0; + else + return 1; + } +} + +/* + * Has file `A' been modified after time `T'? + * + * case: + * + * a newer than t returns 1 + * a older than t returns 0 + * stat on a fails returns -1 + */ +int +is_newer (char *fa, time_t t) +{ + struct stat fa_sb; + register int fa_stat; + register int status = 0; + + fa_stat = stat (fa, &fa_sb); + if (fa_stat != 0) + status = -1; + + if (status != 0) + return status; + + return (fa_sb.st_mtime > t); +} + +/* + * Return to the main command loop in octave.cc. + */ +volatile void +jump_to_top_level (void) +{ + run_all_unwind_protects (); + + longjmp (toplevel, 1); +} + +/* + * Gag. + */ +char * +s_plural (int i) +{ + static char *empty = ""; + static char *s = "s"; + return i == 1 ? empty : s; +} + +char * +es_plural (int i) +{ + static char *empty = ""; + static char *es = "es"; + return i == 1 ? es : empty; +} + +char * +save_in_tmp_file (tree_constant& t, int ndim = 2, int parametric = 0) +{ + char *name = strsave (tmpnam ((char *) NULL)); + if (name != (char *) NULL) + { + ofstream file (name); + if (file) + { + switch (ndim) + { + case 2: + t.save (file); + break; + case 3: + t.save_three_d (file, parametric); + break; + default: + panic_impossible (); + break; + } + } + else + { + error ("couldn't open temporary output file `%s'", name); + delete [] name; + name = (char *) NULL; + } + } + return name; +} + +void +mark_for_deletion (const char *filename) +{ + char *tmp = strsave (filename); + tmp_files.push (tmp); +} + +void +cleanup_tmp_files (void) +{ + while (! tmp_files.empty ()) + { + char *filename = tmp_files.pop (); + unlink (filename); + delete [] filename; + } +} + +int +send_to_plot_stream (const char *cmd) +{ +// From sighandlers.cc: + extern int pipe_handler_error_count; + + static int initialized = 0; + + if (! plot_stream.is_open ()) + { + char *plot_prog = user_pref.gnuplot_binary; + if (plot_prog != (char *) NULL) + { + plot_stream.open (plot_prog); + if (! plot_stream.is_open ()) + { + warning ("plot: unable to open pipe to `%s'", + plot_prog); + + if (strcmp (plot_prog, "gnuplot") != 0) + { + message ("plot", "trying again with `gnuplot'"); + goto last_chance; + } + } + } + else + { + last_chance: + + plot_stream.open ("gnuplot"); + + if (! plot_stream.is_open ()) + { + error ("plot: unable to open pipe to `%s'", plot_prog); + return -1; + } + } + } + + if (! initialized) + { + initialized = 1; + plot_stream << "set data style lines\n"; + } + + plot_stream << cmd; + plot_stream.flush (); + pipe_handler_error_count = 0; + + return 0; +} + +void +close_plot_stream (void) +{ + if (plot_stream.is_open ()) + plot_stream.close (); +} + +int +almost_match (char *std, char *s, int min_match_len = 1) +{ + int stdlen = strlen (std); + int slen = strlen (s); + + return (slen <= stdlen + && slen >= min_match_len + && strncmp (std, s, slen) == 0); +} + +char ** +get_m_file_names (int& num, char *dir, int no_suffix) +{ + static int num_max = 256; + char **retval = new char * [num_max]; + int i = 0; + + DIR *dirp = opendir (dir); + if (dirp != (DIR *) NULL) + { + struct dirent *entry; + while ((entry = readdir (dirp)) != (struct dirent *) NULL) + { + int len = NLENGTH (entry); + if (len > 2 + && entry->d_name[len-2] == '.' + && entry->d_name[len-1] == 'm') + { + retval[i] = strsave (entry->d_name); + if (no_suffix) + retval[i][len-2] = '\0'; + + i++; + + if (i == num_max - 1) + { + num_max += 256; + char **tmp = new char * [num_max]; + for (int j = 0; j < i; j++) + tmp[j] = retval[j]; + + retval = tmp; + } + } + } + free (dirp); + } + + retval[i] = (char *) NULL; + num = i; + + return retval; +} + +char ** +get_m_file_names (int& num, int no_suffix) +{ + static int num_max = 1024; + char **retval = new char * [num_max]; + int i = 0; + + char **path = pathstring_to_vector (user_pref.loadpath); + + char **ptr = path; + if (ptr != (char **) NULL) + { + while (*ptr != (char *) NULL) + { + int tmp_num; + char **names = get_m_file_names (tmp_num, *ptr, no_suffix); + + if (i + tmp_num >= num_max - 1) + { + num_max += 1024; + char **tmp = new char * [num_max]; + for (int j = 0; j < i; j++) + tmp[j] = retval[j]; + + retval = tmp; + } + + int k = 0; + while (k < tmp_num) + retval[i++] = names[k++]; + + ptr++; + } + } + + retval[i] = (char *) NULL; + num = i; + + return retval; +} + +int +NINT (double x) +{ + if (x > INT_MAX) + return INT_MAX; + else if (x < INT_MIN) + return INT_MIN; + else + return (x > 0) ? ((int) (x + 0.5)) : ((int) (x - 0.5)); +} + +double +D_NINT (double x) +{ + if (xisinf (x) || xisnan (x)) + return x; + else + return floor (x + 0.5); +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; page-delimiter: "^/\\*" *** +;;; End: *** +*/