int nextSeqNo()

in src/generic/filecounter.c [329:540]


int nextSeqNo(Tcl_Interp * interp, SeqNoGenerator * seqnogen, int *seqno, int next)
{
  /* if next == 1: incr filecounter, if next == 0: just get current value of filecounter */ 
    int currentSeqNo = -1;
    Tcl_Channel channel;
    Tcl_Obj *lineObj = NULL;
    int bytesRead = -1;
    int newfile = 0;

    if (seqnogen == NULL)
	return TCL_ERROR;

    Tcl_SetResult(interp, "", TCL_STATIC);

    /* ----------------------------------------------------------------------
     * Try to create file
     * ------------------------------------------------------------------- */
    if ((channel = Tcl_OpenFileChannel(interp,
				       seqnogen->fileName,
				       "CREAT RDWR", seqnogen->mask)) == NULL) {

	LOG_MSG(interp, WRITE_LOG,
		__FILE__, __LINE__,
		"web::filecounter", WEBLOG_ERROR,
		(char *) Tcl_GetStringResult(interp), NULL);

	return TCL_ERROR;
    }

    /* --------------------------------------------------------------------
     * Try to lock file
     * ----------------------------------------------------------------- */
    if (lock_TclChannel(interp, channel) == TCL_ERROR) {

	LOG_MSG(interp, WRITE_LOG | SET_RESULT,
		__FILE__, __LINE__,
		"web::filecounter", WEBLOG_ERROR, "error getting lock", NULL);
	return TCL_ERROR;
    }

    /* --------------------------------------------------------------------
     * Try to read file
     * ----------------------------------------------------------------- */
    lineObj = Tcl_NewObj();
    Tcl_IncrRefCount(lineObj);

    if ((bytesRead = Tcl_GetsObj(channel, lineObj)) < 0) {

	if (!Tcl_Eof(channel)) {

	    /* failed -> unlock and close */
	    unlock_TclChannel(interp, channel);
	    Tcl_Close(interp, channel);

	    LOG_MSG(interp, WRITE_LOG | SET_RESULT,
		    __FILE__, __LINE__,
		    "web::filecounter", WEBLOG_ERROR,
		    "error reading file: ", Tcl_ErrnoMsg(Tcl_GetErrno()),
		    NULL);

	    Tcl_DecrRefCount(lineObj);
	    return TCL_ERROR;
	}
	else {
	    bytesRead = 0;
	}
    }

    /* --------------------------------------------------------------------
     * new file
     * ----------------------------------------------------------------- */
    if (bytesRead == 0) {

	LOG_MSG(interp, WRITE_LOG,
		__FILE__, __LINE__,
		"web::filecounter", WEBLOG_INFO, "new file", NULL);

	currentSeqNo = seqnogen->seed;
	newfile = 1;
    }
    else {

	/* --------------------------------------------------------------------
	 * have read
	 * ----------------------------------------------------------------- */
	if (Tcl_GetIntFromObj(interp, lineObj, &currentSeqNo) != TCL_OK) {

	    /* ----------------------------------------------------------------
	     * ... but cannot understand what I read
	     * ------------------------------------------------------------- */
	    unlock_TclChannel(interp, channel);
	    Tcl_Close(interp, channel);

	    LOG_MSG(interp, WRITE_LOG | SET_RESULT,
		    __FILE__, __LINE__,
		    "web::filecounter", WEBLOG_ERROR,
		    "file \"", seqnogen->fileName,
		    "\" contains invalid data: ",
		    Tcl_GetStringResult(interp), NULL);

	    Tcl_DecrRefCount(lineObj);

	    return TCL_ERROR;
	}

	/* --------------------------------------------------------------------
	 * get value (and wrap)
	 * ----------------------------------------------------------------- */
	if (next == 1) {
	  currentSeqNo += seqnogen->incrValue;

	  if (currentSeqNo > seqnogen->maxValue) {

	    if (seqnogen->doWrap) {

		currentSeqNo = seqnogen->minValue;

	    }
	    else {

		unlock_TclChannel(interp, channel);
		Tcl_Close(interp, channel);

		LOG_MSG(interp, WRITE_LOG | SET_RESULT,
			__FILE__, __LINE__,
			"web::filecounter", WEBLOG_ERROR,
			"counter overflow", NULL);

		Tcl_DecrRefCount(lineObj);

		return TCL_ERROR;
	    }
	  }
	}
    }

    /* ------------------------------------------------------------------------
     * set result to return
     * --------------------------------------------------------------------- */
    *seqno = currentSeqNo;

    /* ------------------------------------------------------------------------
     * write new value, but only if we need to:
     * either next == 1 (i.e. we have a new value)
     * or newfile == 1 (we have a new file to write)
     * --------------------------------------------------------------------- */
    if (next == 1 || newfile == 1) {
      Tcl_SetIntObj(lineObj, *seqno);

      if (Tcl_Seek(channel, 0, SEEK_SET) < 0) {

	LOG_MSG(interp, WRITE_LOG | SET_RESULT,
		__FILE__, __LINE__,
		"web::filecounter", WEBLOG_ERROR,
		"error rewinding channel", NULL);

	unlock_TclChannel(interp, channel);
	Tcl_Close(interp, channel);

	Tcl_DecrRefCount(lineObj);

	return TCL_ERROR;
      }

      Tcl_AppendToObj(lineObj, "\n", 1);

      {

	int written = 0;
	int expected = 0;

	written = Tcl_WriteObj(channel, lineObj);
	expected = Tcl_GetCharLength(lineObj);

	/* printf("DBG written: %d, expected: %d\n",written,expected); fflush(stdout); */

	/*   if ( (written = Tcl_WriteObj(channel,lineObj)) != Tcl_GetCharLength(lineObj))  */

	if (written < expected) {

	    /*we try to close the file */
	    unlock_TclChannel(interp, channel);
	    Tcl_Close(interp, channel);

	    LOG_MSG(interp, WRITE_LOG | SET_RESULT,
		    __FILE__, __LINE__,
		    "web::filecounter", WEBLOG_ERROR,
		    "error writing to file \"",
		    seqnogen->fileName, "\": ", Tcl_GetStringResult(interp),
		    NULL);

	    Tcl_DecrRefCount(lineObj);

	    return TCL_ERROR;
	}
      }

      /* ------------------------------------------------------------------------
       * that's it
       * --------------------------------------------------------------------- */
      Tcl_Flush(channel);
    }

    unlock_TclChannel(interp, channel);
    Tcl_Close(interp, channel);

    Tcl_DecrRefCount(lineObj);

    seqnogen->currValue = *seqno;
    seqnogen->hasCurrent = 1;
    return TCL_OK;
}