prepare for the release of rrdtool-1.2.99907080300
[rrdtool.git] / src / rrd_update.c
index eb08f78..1e53979 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.2.99907080300  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_update.c  RRD Update Function
  *****************************************************************************
@@ -14,6 +14,8 @@
 #include <io.h>
 #endif
 
+#include <locale.h>
+
 #include "rrd_hw.h"
 #include "rrd_rpncalc.h"
 
@@ -56,10 +58,10 @@ static int gettimeofday(
 
 #endif
 /*
- * normilize time as returned by gettimeofday. usec part must
+ * normalize time as returned by gettimeofday. usec part must
  * be always >= 0
  */
-static void normalize_time(
+static inline void normalize_time(
     struct timeval *t)
 {
     if (t->tv_usec < 0) {
@@ -68,7 +70,7 @@ static void normalize_time(
     }
 }
 
-static info_t *write_RRA_row(
+static inline info_t *write_RRA_row(
     rrd_file_t *rrd_file,
     rrd_t *rrd,
     unsigned long rra_idx,
@@ -104,7 +106,7 @@ static info_t *write_RRA_row(
         if (rrd_write
             (rrd_file,
              &(rrd->cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val),
-             sizeof(rrd_value_t) * 1) != sizeof(rrd_value_t) * 1) {
+             sizeof(rrd_value_t)) != sizeof(rrd_value_t)) {
             rrd_set_error("writing rrd: %s", rrd_strerror(errno));
             return 0;
         }
@@ -135,16 +137,16 @@ info_t   *rrd_update_v(
     char     *tmplt = NULL;
     info_t   *result = NULL;
     infoval   rc;
+    struct option long_options[] = {
+        {"template", required_argument, 0, 't'},
+        {0, 0, 0, 0}
+    };
 
     rc.u_int = -1;
     optind = 0;
     opterr = 0;         /* initialize getopt */
 
     while (1) {
-        static struct option long_options[] = {
-            {"template", required_argument, 0, 't'},
-            {0, 0, 0, 0}
-        };
         int       option_index = 0;
         int       opt;
 
@@ -183,6 +185,12 @@ int rrd_update(
     int argc,
     char **argv)
 {
+    struct option long_options[] = {
+        {"template", required_argument, 0, 't'},
+        {0, 0, 0, 0}
+    };
+    int       option_index = 0;
+    int       opt;
     char     *tmplt = NULL;
     int       rc;
 
@@ -190,13 +198,6 @@ int rrd_update(
     opterr = 0;         /* initialize getopt */
 
     while (1) {
-        static struct option long_options[] = {
-            {"template", required_argument, 0, 't'},
-            {0, 0, 0, 0}
-        };
-        int       option_index = 0;
-        int       opt;
-
         opt = getopt_long(argc, argv, "t:", long_options, &option_index);
 
         if (opt == EOF)
@@ -204,7 +205,7 @@ int rrd_update(
 
         switch (opt) {
         case 't':
-            tmplt = optarg;
+            tmplt = strdup(optarg);
             break;
 
         case '?':
@@ -222,6 +223,7 @@ int rrd_update(
 
     rc = rrd_update_r(argv[optind], tmplt,
                       argc - optind - 1, (const char **) (argv + optind + 1));
+    free(tmplt);
     return rc;
 }
 
@@ -271,7 +273,7 @@ int _rrd_update(
     rrd_value_t *pdp_new;   /* prepare the incoming data
                              * to be added the the
                              * existing entry */
-    rrd_value_t *pdp_temp;  /* prepare the pdp values 
+    rrd_value_t *pdp_temp;  /* prepare the pdp values
                              * to be added the the
                              * cdp values */
 
@@ -318,13 +320,15 @@ int _rrd_update(
     /* need at least 1 arguments: data. */
     if (argc < 1) {
         rrd_set_error("Not enough arguments");
-        return -1;
+        goto err_out;
     }
 
     rrd_file = rrd_open(filename, &rrd, RRD_READWRITE);
     if (rrd_file == NULL) {
-        return -1;
+        goto err_free;
     }
+    /* We are now at the beginning of the rra's */
+    rra_current = rra_start = rra_begin = rrd_file->header_len;
 
     /* initialize time */
     version = atoi(rrd.stat_head->version);
@@ -337,61 +341,30 @@ int _rrd_update(
         current_time_usec = 0;
     }
 
-    rra_current = rra_start = rra_begin = rrd_file->header_len;
-    /* This is defined in the ANSI C standard, section 7.9.5.3:
-
-       When a file is opened with udpate mode ('+' as the second
-       or third character in the ... list of mode argument
-       variables), both input and output may be performed on the
-       associated stream.  However, ...  input may not be directly
-       followed by output without an intervening call to a file
-       positioning function, unless the input operation encounters
-       end-of-file. */
-#if 0                   //def HAVE_MMAP
-    rrd_filesize = rrd_file->file_size;
-    fseek(rrd_file->fd, 0, SEEK_END);
-    rrd_filesize = ftell(rrd_file->fd);
-    fseek(rrd_file->fd, rra_current, SEEK_SET);
-#else
-//    fseek(rrd_file->fd, 0, SEEK_CUR);
-#endif
-
-
     /* get exclusive lock to whole file.
      * lock gets removed when we close the file.
      */
     if (LockRRD(rrd_file->fd) != 0) {
         rrd_set_error("could not lock RRD");
-        rrd_free(&rrd);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_close;
     }
 
     if ((updvals =
          malloc(sizeof(char *) * (rrd.stat_head->ds_cnt + 1))) == NULL) {
         rrd_set_error("allocating updvals pointer array");
-        rrd_free(&rrd);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_close;
     }
 
     if ((pdp_temp = malloc(sizeof(rrd_value_t)
                            * rrd.stat_head->ds_cnt)) == NULL) {
         rrd_set_error("allocating pdp_temp ...");
-        free(updvals);
-        rrd_free(&rrd);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_updvals;
     }
 
     if ((tmpl_idx = malloc(sizeof(unsigned long)
                            * (rrd.stat_head->ds_cnt + 1))) == NULL) {
         rrd_set_error("allocating tmpl_idx ...");
-        free(pdp_temp);
-        free(updvals);
-        rrd_free(&rrd);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_pdp_temp;
     }
     /* initialize tmplt redirector */
     /* default config example (assume DS 1 is a CDEF DS)
@@ -421,22 +394,11 @@ int _rrd_update(
                 if (tmpl_cnt > rrd.stat_head->ds_cnt) {
                     rrd_set_error
                         ("tmplt contains more DS definitions than RRD");
-                    free(updvals);
-                    free(pdp_temp);
-                    free(tmpl_idx);
-                    rrd_free(&rrd);
-                    close(rrd_file->fd);
-                    return (-1);
+                    goto err_free_tmpl_idx;
                 }
                 if ((tmpl_idx[tmpl_cnt++] = ds_match(&rrd, dsname)) == -1) {
                     rrd_set_error("unknown DS name '%s'", dsname);
-                    free(updvals);
-                    free(pdp_temp);
-                    free(tmplt_copy);
-                    free(tmpl_idx);
-                    rrd_free(&rrd);
-                    close(rrd_file->fd);
-                    return (-1);
+                    goto err_free_tmpl_idx;
                 } else {
                     /* the first element is always the time */
                     tmpl_idx[tmpl_cnt - 1]++;
@@ -455,33 +417,8 @@ int _rrd_update(
     if ((pdp_new = malloc(sizeof(rrd_value_t)
                           * rrd.stat_head->ds_cnt)) == NULL) {
         rrd_set_error("allocating pdp_new ...");
-        free(updvals);
-        free(pdp_temp);
-        free(tmpl_idx);
-        rrd_free(&rrd);
-        close(rrd_file->fd);
-        return (-1);
-    }
-#if 0                   //def HAVE_MMAP
-    rrd_mmaped_file = mmap(0,
-                           rrd_file->file_len,
-                           PROT_READ | PROT_WRITE,
-                           MAP_SHARED, fileno(in_file), 0);
-    if (rrd_mmaped_file == MAP_FAILED) {
-        rrd_set_error("error mmapping file %s", filename);
-        free(updvals);
-        free(pdp_temp);
-        free(tmpl_idx);
-        rrd_free(&rrd);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_tmpl_idx;
     }
-#ifdef USE_MADVISE
-    /* when we use mmaping we tell the kernel the mmap equivalent
-       of POSIX_FADV_RANDOM */
-    madvise(rrd_mmaped_file, rrd_filesize, POSIX_MADV_RANDOM);
-#endif
-#endif
     /* loop through the arguments. */
     for (arg_i = 0; arg_i < argc; arg_i++) {
         char     *stepper = strdup(argv[arg_i]);
@@ -494,15 +431,7 @@ int _rrd_update(
         if (stepper == NULL) {
             rrd_set_error("failed duplication argv entry");
             free(step_start);
-            free(updvals);
-            free(pdp_temp);
-            free(tmpl_idx);
-            rrd_free(&rrd);
-#ifdef HAVE_MMAP
-            rrd_close(rrd_file);
-#endif
-            close(rrd_file->fd);
-            return (-1);
+            goto err_free_pdp_new;
         }
         /* initialize all ds input to unknown except the first one
            which has always got to be set */
@@ -573,8 +502,11 @@ int _rrd_update(
             current_time_usec = tmp_time.tv_usec;
         } else {
             double    tmp;
+            char     *old_locale;
 
+            old_locale = setlocale(LC_NUMERIC, "C");
             tmp = strtod(updvals[0], 0);
+            setlocale(LC_NUMERIC, old_locale);
             current_time = floor(tmp);
             current_time_usec =
                 (long) ((tmp - (double) current_time) * 1000000.0);
@@ -594,7 +526,6 @@ int _rrd_update(
             break;
         }
 
-
         /* seek to the beginning of the rra's */
         if (rra_current != rra_begin) {
 #ifndef HAVE_MMAP
@@ -660,40 +591,37 @@ int _rrd_update(
 
             /* NOTE: DST_CDEF should never enter this if block, because
              * updvals[i+1][0] is initialized to 'U'; unless the caller
-             * accidently specified a value for the DST_CDEF. To handle 
+             * accidently specified a value for the DST_CDEF. To handle
              * this case, an extra check is required. */
 
             if ((updvals[i + 1][0] != 'U') &&
                 (dst_idx != DST_CDEF) &&
                 rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt >= interval) {
                 double    rate = DNAN;
+                char     *old_locale;
 
                 /* the data source type defines how to process the data */
                 /* pdp_new contains rate * time ... eg the bytes
                  * transferred during the interval. Doing it this way saves
                  * a lot of math operations */
-
-
                 switch (dst_idx) {
                 case DST_COUNTER:
                 case DST_DERIVE:
-                    if (rrd.pdp_prep[i].last_ds[0] != 'U') {
-                        for (ii = 0; updvals[i + 1][ii] != '\0'; ii++) {
-                            if ((updvals[i + 1][ii] < '0'
-                                 || updvals[i + 1][ii] > '9') && (ii != 0
-                                                                  && updvals[i
-                                                                             +
-                                                                             1]
-                                                                  [ii] !=
-                                                                  '-')) {
-                                rrd_set_error("not a simple integer: '%s'",
-                                              updvals[i + 1]);
-                                break;
-                            }
-                        }
-                        if (rrd_test_error()) {
+                    for (ii = 0; updvals[i + 1][ii] != '\0'; ii++) {
+                        if ((updvals[i + 1][ii] < '0'
+                             || updvals[i + 1][ii] > '9') && (ii != 0
+                                                              && updvals[i
+                                                                         + 1]
+                                                              [ii] != '-')) {
+                            rrd_set_error("not a simple integer: '%s'",
+                                          updvals[i + 1]);
                             break;
                         }
+                    }
+                    if (rrd_test_error()) {
+                        break;
+                    }
+                    if (rrd.pdp_prep[i].last_ds[0] != 'U') {
                         pdp_new[i] =
                             rrd_diff(updvals[i + 1], rrd.pdp_prep[i].last_ds);
                         if (dst_idx == DST_COUNTER) {
@@ -712,10 +640,12 @@ int _rrd_update(
                     }
                     break;
                 case DST_ABSOLUTE:
+                    old_locale = setlocale(LC_NUMERIC, "C");
                     errno = 0;
                     pdp_new[i] = strtod(updvals[i + 1], &endptr);
+                    setlocale(LC_NUMERIC, old_locale);
                     if (errno > 0) {
-                        rrd_set_error("converting  '%s' to float: %s",
+                        rrd_set_error("converting '%s' to float: %s",
                                       updvals[i + 1], rrd_strerror(errno));
                         break;
                     };
@@ -729,9 +659,11 @@ int _rrd_update(
                     break;
                 case DST_GAUGE:
                     errno = 0;
+                    old_locale = setlocale(LC_NUMERIC, "C");
                     pdp_new[i] = strtod(updvals[i + 1], &endptr) * interval;
+                    setlocale(LC_NUMERIC, old_locale);
                     if (errno > 0) {
-                        rrd_set_error("converting  '%s' to float: %s",
+                        rrd_set_error("converting '%s' to float: %s",
                                       updvals[i + 1], rrd_strerror(errno));
                         break;
                     };
@@ -817,21 +749,21 @@ int _rrd_update(
         } else {
             /* an pdp_st has occurred. */
 
-            /* in pdp_prep[].scratch[PDP_val].u_val we have collected rate*seconds which 
-             * occurred up to the last run.        
-             pdp_new[] contains rate*seconds from the latest run.
-             pdp_temp[] will contain the rate for cdp */
+            /* in pdp_prep[].scratch[PDP_val].u_val we have collected
+               rate*seconds which occurred up to the last run.
+               pdp_new[] contains rate*seconds from the latest run.
+               pdp_temp[] will contain the rate for cdp */
 
             for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
                 /* update pdp_prep to the current pdp_st. */
                 double    pre_unknown = 0.0;
 
-                if (isnan(pdp_new[i]))
+                if (isnan(pdp_new[i])) {
                     /* a final bit of unkonwn to be added bevore calculation
-                     * we use a tempaorary variable for this so that we 
-                     * don't have to turn integer lines before using the value */
+                       we use a temporary variable for this so that we
+                       don't have to turn integer lines before using the value */
                     pre_unknown = pre_int;
-                else {
+                else {
                     if (isnan(rrd.pdp_prep[i].scratch[PDP_val].u_val)) {
                         rrd.pdp_prep[i].scratch[PDP_val].u_val =
                             pdp_new[i] / interval * pre_int;
@@ -844,9 +776,9 @@ int _rrd_update(
 
                 /* if too much of the pdp_prep is unknown we dump it */
                 if (
-                       /* removed because this does not agree with the definition
-                          a heart beat can be unknown */
-                       /* (rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt 
+                       /* removed because this does not agree with the
+                          definition that a heartbeat can be unknown */
+                       /* (rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt
                           > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) || */
                        /* if the interval is larger thatn mrhb we get NAN */
                        (interval > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) ||
@@ -944,16 +876,17 @@ int _rrd_update(
                 }
 
                 if (current_cf == CF_SEASONAL || current_cf == CF_DEVSEASONAL) {
-                    /* If this is a bulk update, we need to skip ahead in the seasonal
-                     * arrays so that they will be correct for the next observed value;
-                     * note that for the bulk update itself, no update will occur to
-                     * DEVSEASONAL or SEASONAL; futhermore, HWPREDICT and DEVPREDICT will
-                     * be set to DNAN. */
+                    /* If this is a bulk update, we need to skip ahead in
+                       the seasonal arrays so that they will be correct for
+                       the next observed value;
+                       note that for the bulk update itself, no update will
+                       occur to DEVSEASONAL or SEASONAL; futhermore, HWPREDICT
+                       and DEVPREDICT will be set to DNAN. */
                     if (rra_step_cnt[i] > 2) {
                         /* skip update by resetting rra_step_cnt[i],
-                         * note that this is not data source specific; this is due
-                         * to the bulk update, not a DNAN value for the specific data
-                         * source. */
+                           note that this is not data source specific; this is
+                           due to the bulk update, not a DNAN value for the
+                           specific data source. */
                         rra_step_cnt[i] = 0;
                         lookup_seasonal(&rrd, i, rra_start, rrd_file,
                                         elapsed_pdp_st, &last_seasonal_coef);
@@ -1273,6 +1206,7 @@ int _rrd_update(
                                     u_val = seasonal_coef[ii];
                                 break;
                             case CF_HWPREDICT:
+                            case CF_MHWPREDICT:
                                 /* need to update the null_count and last_null_count.
                                  * even do this for non-DNAN pdp_temp because the
                                  * algorithm is not learning from batch updates. */
@@ -1371,12 +1305,10 @@ int _rrd_update(
                     (rrd.stat_head->ds_cnt) * (rrd.rra_ptr[i].cur_row) *
                     sizeof(rrd_value_t);
                 if (rra_pos_tmp != rra_current) {
-#ifndef HAVE_MMAP
                     if (rrd_seek(rrd_file, rra_pos_tmp, SEEK_SET) != 0) {
                         rrd_set_error("seek error in rrd");
                         break;
                     }
-#endif
                     rra_current = rra_pos_tmp;
                 }
 #ifdef DEBUG
@@ -1458,23 +1390,13 @@ int _rrd_update(
         free(rra_step_cnt);
     rpnstack_free(&rpnstack);
 
-#if 0                   //def HAVE_MMAP
-    if (munmap(rrd_file->file_start, rrd_file->file_len) == -1) {
-        rrd_set_error("error writing(unmapping) file: %s", filename);
-    }
-#else
-    rrd_flush(rrd_file);    //XXX: really needed?
+#if 0
+    //rrd_flush(rrd_file);    //XXX: really needed?
 #endif
     /* if we got here and if there is an error and if the file has not been
      * written to, then close things up and return. */
     if (rrd_test_error()) {
-        free(updvals);
-        free(tmpl_idx);
-        rrd_free(&rrd);
-        free(pdp_temp);
-        free(pdp_new);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_pdp_new;
     }
 
     /* aargh ... that was tough ... so many loops ... anyway, its done.
@@ -1485,38 +1407,22 @@ int _rrd_update(
                             + sizeof(rra_def_t) * rrd.stat_head->rra_cnt),
                  SEEK_SET) != 0) {
         rrd_set_error("seek rrd for live header writeback");
-        free(updvals);
-        free(tmpl_idx);
-        rrd_free(&rrd);
-        free(pdp_temp);
-        free(pdp_new);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_pdp_new;
     }
-
+    /* for mmap, we did already write to the underlying mapping, so we do
+       not need to write again.  */
+#ifndef HAVE_MMAP
     if (version >= 3) {
         if (rrd_write(rrd_file, rrd.live_head,
                       sizeof(live_head_t) * 1) != sizeof(live_head_t) * 1) {
             rrd_set_error("rrd_write live_head to rrd");
-            free(updvals);
-            rrd_free(&rrd);
-            free(tmpl_idx);
-            free(pdp_temp);
-            free(pdp_new);
-            close(rrd_file->fd);
-            return (-1);
+            goto err_free_pdp_new;
         }
     } else {
         if (rrd_write(rrd_file, &rrd.live_head->last_up,
                       sizeof(time_t) * 1) != sizeof(time_t) * 1) {
             rrd_set_error("rrd_write live_head to rrd");
-            free(updvals);
-            rrd_free(&rrd);
-            free(tmpl_idx);
-            free(pdp_temp);
-            free(pdp_new);
-            close(rrd_file->fd);
-            return (-1);
+            goto err_free_pdp_new;
         }
     }
 
@@ -1525,13 +1431,7 @@ int _rrd_update(
                   sizeof(pdp_prep_t) * rrd.stat_head->ds_cnt)
         != (ssize_t) (sizeof(pdp_prep_t) * rrd.stat_head->ds_cnt)) {
         rrd_set_error("rrd_write pdp_prep to rrd");
-        free(updvals);
-        rrd_free(&rrd);
-        free(tmpl_idx);
-        free(pdp_temp);
-        free(pdp_new);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_pdp_new;
     }
 
     if (rrd_write(rrd_file, rrd.cdp_prep,
@@ -1541,42 +1441,18 @@ int _rrd_update(
                       rrd.stat_head->ds_cnt)) {
 
         rrd_set_error("rrd_write cdp_prep to rrd");
-        free(updvals);
-        free(tmpl_idx);
-        rrd_free(&rrd);
-        free(pdp_temp);
-        free(pdp_new);
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_pdp_new;
     }
 
     if (rrd_write(rrd_file, rrd.rra_ptr,
                   sizeof(rra_ptr_t) * rrd.stat_head->rra_cnt)
         != (ssize_t) (sizeof(rra_ptr_t) * rrd.stat_head->rra_cnt)) {
         rrd_set_error("rrd_write rra_ptr to rrd");
-        free(updvals);
-        free(tmpl_idx);
-        rrd_free(&rrd);
-        free(pdp_temp);
-        free(pdp_new);
-        close(rrd_file->fd);
-        return (-1);
-    }
-#ifdef HAVE_POSIX_FADVISExxx
-
-    /* with update we have write ops, so they will probably not be done by now, this means
-       the buffers will not get freed. But calling this for the whole file - header
-       will let the data off the hook as soon as it is written when if it is from a previous
-       update cycle. Calling fdsync to force things is much too hard here. */
-
-    if (0 != posix_fadvise(rrd_file->fd, rra_begin, 0, POSIX_FADV_DONTNEED)) {
-        rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s", filename,
-                      rrd_strerror(errno));
-        close(rrd_file->fd);
-        return (-1);
+        goto err_free_pdp_new;
     }
 #endif
-    /*XXX: ? */ rrd_flush(rrd_file);
+
+    /* rrd_flush(rrd_file); */
 
     /* calling the smoothing code here guarantees at most
      * one smoothing operation per rrd_update call. Unfortunately,
@@ -1584,8 +1460,6 @@ int _rrd_update(
      * for smoothing to occur off-schedule. This really isn't
      * critical except during the burning cycles. */
     if (schedule_smooth) {
-//    in_file = fopen(filename,"rb+");
-
 
         rra_start = rra_begin;
         for (i = 0; i < rrd.stat_head->rra_cnt; ++i) {
@@ -1601,25 +1475,32 @@ int _rrd_update(
             rra_start += rrd.rra_def[i].row_cnt
                 * rrd.stat_head->ds_cnt * sizeof(rrd_value_t);
         }
-#ifdef HAVE_POSIX_FADVISExxx
-        /* same procedure as above ... */
-        if (0 !=
-            posix_fadvise(rrd_file->fd, rra_begin, 0, POSIX_FADV_DONTNEED)) {
-            rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s", filename,
-                          rrd_strerror(errno));
-            close(rrd_file->fd);
-            return (-1);
-        }
-#endif
     }
 
-    rrd_close(rrd_file);
+/*    rrd_dontneed(rrd_file,&rrd); */
     rrd_free(&rrd);
-    free(updvals);
-    free(tmpl_idx);
+    rrd_close(rrd_file);
+
     free(pdp_new);
+    free(tmpl_idx);
     free(pdp_temp);
+    free(updvals);
     return (0);
+
+  err_free_pdp_new:
+    free(pdp_new);
+  err_free_tmpl_idx:
+    free(tmpl_idx);
+  err_free_pdp_temp:
+    free(pdp_temp);
+  err_free_updvals:
+    free(updvals);
+  err_close:
+    rrd_close(rrd_file);
+  err_free:
+    rrd_free(&rrd);
+  err_out:
+    return (-1);
 }
 
 /*