e99772f9bf09219c532812c859fbeea513c67e65vboxsync/* $Id$ */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/** @file
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * IPRT Testcase / Tool - Source Code Massager Stream Code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Copyright (C) 2010-2012 Oracle Corporation
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * available from http://www.virtualbox.org. This file is free software;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * General Public License (GPL) as published by the Free Software
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/*******************************************************************************
e99772f9bf09219c532812c859fbeea513c67e65vboxsync* Header Files *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync*******************************************************************************/
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/assert.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/ctype.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/err.h>
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#include <iprt/file.h>
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#include <iprt/handle.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/mem.h>
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#include <iprt/pipe.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/string.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include "scmstream.h"
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Initializes the stream structure.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream structure.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param fWriteOrRead The value of the fWriteOrRead stream member.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic void scmStreamInitInternal(PSCMSTREAM pStream, bool fWriteOrRead)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch = NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cb = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cbAllocated = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines = NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLines = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLinesAllocated = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fWriteOrRead = fWriteOrRead;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fFileMemory = false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fFullyLineated = false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->rc = VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Initialize an input stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream to initialize.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pszFilename The file to take the stream content from.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamInitForReading(PSCMSTREAM pStream, const char *pszFilename)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync scmStreamInitInternal(pStream, false /*fWriteOrRead*/);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync void *pvFile;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cbFile;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = pStream->rc = RTFileReadAll(pszFilename, &pvFile, &cbFile);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_SUCCESS(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch = (char *)pvFile;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cb = cbFile;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cbAllocated = cbFile;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fFileMemory = true;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Initialize an output stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream to initialize.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pRelatedStream Pointer to a related stream. NULL is fine.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamInitForWriting(PSCMSTREAM pStream, PCSCMSTREAM pRelatedStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync scmStreamInitInternal(pStream, true /*fWriteOrRead*/);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* allocate stuff */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cbEstimate = pRelatedStream
e99772f9bf09219c532812c859fbeea513c67e65vboxsync ? pRelatedStream->cb + pRelatedStream->cb / 10
e99772f9bf09219c532812c859fbeea513c67e65vboxsync : _64K;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cbEstimate = RT_ALIGN(cbEstimate, _4K);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch = (char *)RTMemAlloc(cbEstimate);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pStream->pch)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cLinesEstimate = pRelatedStream && pRelatedStream->fFullyLineated
e99772f9bf09219c532812c859fbeea513c67e65vboxsync ? pRelatedStream->cLines + pRelatedStream->cLines / 10
e99772f9bf09219c532812c859fbeea513c67e65vboxsync : cbEstimate / 24;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cLinesEstimate = RT_ALIGN(cLinesEstimate, 512);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines = (PSCMSTREAMLINE)RTMemAlloc(cLinesEstimate * sizeof(SCMSTREAMLINE));
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pStream->paLines)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[0].off = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[0].cch = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[0].enmEol = SCMEOL_NONE;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cbAllocated = cbEstimate;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLinesAllocated = cLinesEstimate;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pStream->pch);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch = NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc = VERR_NO_MEMORY;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Frees the resources associated with the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Nothing is happens to whatever the stream was initialized from or dumped to.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream to delete.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncvoid ScmStreamDelete(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pStream->pch)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pStream->fFileMemory)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTFileReadAllFree(pStream->pch, pStream->cbAllocated);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pStream->pch);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch = NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cbAllocated = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pStream->paLines)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pStream->paLines);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines = NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLinesAllocated = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get the stream status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamGetStatus(PCSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Grows the buffer of a write stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in write mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cbAppending The minimum number of bytes to grow the buffer
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * with.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic int scmStreamGrowBuffer(PSCMSTREAM pStream, size_t cbAppending)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cbAllocated = pStream->cbAllocated;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cbAllocated += RT_MAX(0x1000 + cbAppending, cbAllocated);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cbAllocated = RT_ALIGN(cbAllocated, 0x1000);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync void *pvNew;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pStream->fFileMemory)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pvNew = RTMemRealloc(pStream->pch, cbAllocated);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pvNew)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc = VERR_NO_MEMORY;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pvNew = RTMemDupEx(pStream->pch, pStream->off, cbAllocated - pStream->off);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pvNew)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc = VERR_NO_MEMORY;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTFileReadAllFree(pStream->pch, pStream->cbAllocated);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fFileMemory = false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch = (char *)pvNew;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cbAllocated = cbAllocated;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Grows the line array of a stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param iMinLine Minimum line number.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic int scmStreamGrowLines(PSCMSTREAM pStream, size_t iMinLine)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cLinesAllocated = pStream->cLinesAllocated;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cLinesAllocated += RT_MAX(512 + iMinLine, cLinesAllocated);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cLinesAllocated = RT_ALIGN(cLinesAllocated, 512);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync void *pvNew = RTMemRealloc(pStream->paLines, cLinesAllocated * sizeof(SCMSTREAMLINE));
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pvNew)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc = VERR_NO_MEMORY;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines = (PSCMSTREAMLINE)pvNew;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLinesAllocated = cLinesAllocated;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Rewinds the stream and sets the mode to read.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncvoid ScmStreamRewindForReading(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fWriteOrRead = false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->rc = VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Rewinds the stream and sets the mode to write.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncvoid ScmStreamRewindForWriting(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLines = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fWriteOrRead = true;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fFullyLineated = true;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->rc = VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Checks if it's a text stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Not 100% proof.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns true if it probably is a text file, false if not.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Write or read, doesn't matter.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncbool ScmStreamIsText(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RTStrEnd(pStream->pch, pStream->cb))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pStream->cb)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return true;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Performs an integrity check of the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamCheckItegrity(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Perform sanity checks.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t const cbFile = pStream->cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (size_t iLine = 0; iLine < pStream->cLines; iLine++)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t offEol = pStream->paLines[iLine].off + pStream->paLines[iLine].cch;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(offEol + pStream->paLines[iLine].enmEol <= cbFile, VERR_INTERNAL_ERROR_2);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync switch (pStream->paLines[iLine].enmEol)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case SCMEOL_LF:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->pch[offEol] == '\n', VERR_INTERNAL_ERROR_3);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case SCMEOL_CRLF:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->pch[offEol] == '\r', VERR_INTERNAL_ERROR_3);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->pch[offEol + 1] == '\n', VERR_INTERNAL_ERROR_3);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case SCMEOL_NONE:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(iLine + 1 >= pStream->cLines, VERR_INTERNAL_ERROR_4);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync default:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(iLine + 1 >= pStream->cLines, VERR_INTERNAL_ERROR_5);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Writes the stream to a file.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pszFilenameFmt The filename format string.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param ... Format arguments.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamWriteToFile(PSCMSTREAM pStream, const char *pszFilenameFmt, ...)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#ifdef RT_STRICT
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Check that what we're going to write makes sense first.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = ScmStreamCheckItegrity(pStream);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Do the actual writing.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTFILE hFile;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync va_list va;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync va_start(va, pszFilenameFmt);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = RTFileOpenV(&hFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE, pszFilenameFmt, va);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_SUCCESS(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = RTFileWrite(hFile, pStream->pch, pStream->cb, NULL);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTFileClose(hFile);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync/**
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Writes the stream to standard output.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync *
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * @returns IPRT status code
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * @param pStream The stream.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync */
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsyncint ScmStreamWriteToStdOut(PSCMSTREAM pStream)
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync{
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync int rc;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#ifdef RT_STRICT
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync /*
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Check that what we're going to write makes sense first.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync */
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync rc = ScmStreamCheckItegrity(pStream);
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync if (RT_FAILURE(rc))
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync return rc;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#endif
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync /*
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Do the actual writing.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync */
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync RTHANDLE h;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync rc = RTHandleGetStandard(RTHANDLESTD_OUTPUT, &h);
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync if (RT_SUCCESS(rc))
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync {
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync switch (h.enmType)
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync {
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync case RTHANDLETYPE_FILE:
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync rc = RTFileWrite(h.u.hFile, pStream->pch, pStream->cb, NULL);
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync break;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync case RTHANDLETYPE_PIPE:
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync rc = RTPipeWriteBlocking(h.u.hPipe, pStream->pch, pStream->cb, NULL);
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync break;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync default:
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync rc = VERR_INVALID_HANDLE;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync break;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync }
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync }
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync return rc;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync}
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Worker for ScmStreamGetLine that builds the line number index while parsing
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns Same as SCMStreamGetLine.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pcchLine Where to return the line length.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param penmEol Where to return the kind of end of line marker.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic const char *scmStreamGetLineInternal(PSCMSTREAM pStream, size_t *pcchLine, PSCMEOL penmEol)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(!pStream->fWriteOrRead, NULL);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t off = pStream->off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cb = pStream->cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(off >= cb))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->fFullyLineated = true;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t iLine = pStream->iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(iLine >= pStream->cLinesAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamGrowLines(pStream, iLine);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].off = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cb -= off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchRet = &pStream->pch[off];
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pch = (const char *)memchr(pchRet, '\n', cb);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_LIKELY(pch))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cb = pch - pchRet;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = off + cb + 1;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if ( cb < 1
e99772f9bf09219c532812c859fbeea513c67e65vboxsync || pch[-1] != '\r')
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = *penmEol = SCMEOL_LF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = *penmEol = SCMEOL_CRLF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cb--;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = off + cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = *penmEol = SCMEOL_NONE;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *pcchLine = cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch = cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLines = pStream->iLine = ++iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pchRet;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Internal worker that delineates a stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Caller must check that it is in
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic int scmStreamLineate(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Save the stream position. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t const offSaved = pStream->off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t const iLineSaved = pStream->iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Get each line. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync SCMEOL enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync while (scmStreamGetLineInternal(pStream, &cchLine, &enmEol))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* nothing */;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync Assert(RT_FAILURE(pStream->rc) || pStream->fFullyLineated);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Restore the position */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = offSaved;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = iLineSaved;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get the current stream position as an byte offset.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns The current byte offset
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncsize_t ScmStreamTell(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get the current stream position as a line number.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns The current line (0-based).
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncsize_t ScmStreamTellLine(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync/**
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync * Gets the stream offset of a given line.
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync *
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync * @returns The offset of the line, or the stream size if the line number is too
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync * high.
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync * @param pStream The stream. Must be in read mode.
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync * @param iLine The line we're asking about.
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync */
b20cc298c1a3191a4e6ce780c19313117902675dvboxsyncsize_t ScmStreamTellOffsetOfLine(PSCMSTREAM pStream, size_t iLine)
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync{
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync AssertReturn(!pStream->fWriteOrRead, pStream->cb);
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync if (!pStream->fFullyLineated)
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync {
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync int rc = scmStreamLineate(pStream);
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync AssertRCReturn(rc, pStream->cb);
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync }
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync if (iLine >= pStream->cLines)
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync return pStream->cb;
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync return pStream->paLines[iLine].off;
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync}
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get the current stream size in bytes.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns Count of bytes.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncsize_t ScmStreamSize(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Gets the number of lines in the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns The number of lines.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncsize_t ScmStreamCountLines(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pStream->fFullyLineated)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync scmStreamLineate(pStream);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->cLines;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Seeks to a given byte offset in the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @retval VERR_SEEK if the new stream position is the middle of an EOL marker.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * This is a temporary restriction.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param offAbsolute The offset to seek to. If this is beyond the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * end of the stream, the position is set to the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * end.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamSeekAbsolute(PSCMSTREAM pStream, size_t offAbsolute)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(!pStream->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Must be fully delineated. (lazy bird) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(!pStream->fFullyLineated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamLineate(pStream);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Ok, do the job. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (offAbsolute < pStream->cb)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** @todo Should do a binary search here, but I'm too darn lazy tonight. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = ~(size_t)0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (size_t i = 0; i < pStream->cLines; i++)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (offAbsolute < pStream->paLines[i].off + pStream->paLines[i].cch + pStream->paLines[i].enmEol)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = offAbsolute;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = i;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (offAbsolute > pStream->paLines[i].off + pStream->paLines[i].cch)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc = VERR_SEEK;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->off != ~(size_t)0, pStream->rc = VERR_INTERNAL_ERROR_3);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = pStream->cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = pStream->cLines;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Seeks a number of bytes relative to the current stream position.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @retval VERR_SEEK if the new stream position is the middle of an EOL marker.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * This is a temporary restriction.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param offRelative The offset to seek to. A negative offset
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * rewinds and positive one fast forwards the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * stream. Will quietly stop at the beginning and
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * end of the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamSeekRelative(PSCMSTREAM pStream, ssize_t offRelative)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t offAbsolute;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (offRelative >= 0)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync offAbsolute = pStream->off + offRelative;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else if ((size_t)-offRelative <= pStream->off)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync offAbsolute = pStream->off + offRelative;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync offAbsolute = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return ScmStreamSeekAbsolute(pStream, offAbsolute);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Seeks to a given line in the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param iLine The line to seek to. If this is beyond the end
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * of the stream, the position is set to the end.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamSeekByLine(PSCMSTREAM pStream, size_t iLine)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(!pStream->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Must be fully delineated. (lazy bird) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(!pStream->fFullyLineated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamLineate(pStream);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Ok, do the job. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (iLine < pStream->cLines)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = pStream->paLines[iLine].off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = pStream->cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = pStream->cLines;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
711c3306c03131891af1dbbe733668098e1cdef9vboxsync/**
711c3306c03131891af1dbbe733668098e1cdef9vboxsync * Checks if the stream position is at the start of a line.
711c3306c03131891af1dbbe733668098e1cdef9vboxsync *
711c3306c03131891af1dbbe733668098e1cdef9vboxsync * @returns @c true if at the start, @c false if not.
711c3306c03131891af1dbbe733668098e1cdef9vboxsync * @param pStream The stream.
711c3306c03131891af1dbbe733668098e1cdef9vboxsync */
711c3306c03131891af1dbbe733668098e1cdef9vboxsyncbool ScmStreamIsAtStartOfLine(PSCMSTREAM pStream)
711c3306c03131891af1dbbe733668098e1cdef9vboxsync{
711c3306c03131891af1dbbe733668098e1cdef9vboxsync if ( !pStream->fFullyLineated
711c3306c03131891af1dbbe733668098e1cdef9vboxsync && !pStream->fWriteOrRead)
711c3306c03131891af1dbbe733668098e1cdef9vboxsync {
711c3306c03131891af1dbbe733668098e1cdef9vboxsync int rc = scmStreamLineate(pStream);
711c3306c03131891af1dbbe733668098e1cdef9vboxsync if (RT_FAILURE(rc))
711c3306c03131891af1dbbe733668098e1cdef9vboxsync return false;
711c3306c03131891af1dbbe733668098e1cdef9vboxsync }
711c3306c03131891af1dbbe733668098e1cdef9vboxsync return pStream->off == pStream->paLines[pStream->iLine].off;
711c3306c03131891af1dbbe733668098e1cdef9vboxsync}
711c3306c03131891af1dbbe733668098e1cdef9vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get a numbered line from the stream (changes the position).
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * A line is always delimited by a LF character or the end of the stream. The
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * delimiter is not included in returned line length, but instead returned via
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * the @a penmEol indicator.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns Pointer to the first character in the line, not NULL terminated.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * NULL if the end of the stream has been reached or some problem
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * occurred.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param iLine The line to get (0-based).
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pcchLine The length.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param penmEol Where to return the end of line type indicator.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncconst char *ScmStreamGetLineByNo(PSCMSTREAM pStream, size_t iLine, size_t *pcchLine, PSCMEOL penmEol)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(!pStream->fWriteOrRead, NULL);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Make sure it's fully delineated so we can use the index. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(!pStream->fFullyLineated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamLineate(pStream);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* End of stream? */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(iLine >= pStream->cLines))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = pStream->cb;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = pStream->cLines;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return NULL;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Get the data. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchRet = &pStream->pch[pStream->paLines[iLine].off];
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *pcchLine = pStream->paLines[iLine].cch;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *penmEol = pStream->paLines[iLine].enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* update the stream position. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = pStream->paLines[iLine].off + pStream->paLines[iLine].cch + pStream->paLines[iLine].enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = iLine + 1;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pchRet;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get a line from the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * A line is always delimited by a LF character or the end of the stream. The
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * delimiter is not included in returned line length, but instead returned via
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * the @a penmEol indicator.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns Pointer to the first character in the line, not NULL terminated.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * NULL if the end of the stream has been reached or some problem
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * occurred.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pcchLine The length.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param penmEol Where to return the end of line type indicator.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncconst char *ScmStreamGetLine(PSCMSTREAM pStream, size_t *pcchLine, PSCMEOL penmEol)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pStream->fFullyLineated)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return scmStreamGetLineInternal(pStream, pcchLine, penmEol);
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync size_t offCur = pStream->off;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync size_t iCurLine = pStream->iLine;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync const char *pszLine = ScmStreamGetLineByNo(pStream, iCurLine, pcchLine, penmEol);
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync if ( pszLine
768888227f95954ce8676ae279645fae10e24ba2vboxsync && offCur > pStream->paLines[iCurLine].off)
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync {
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync offCur -= pStream->paLines[iCurLine].off;
768888227f95954ce8676ae279645fae10e24ba2vboxsync Assert(offCur <= pStream->paLines[iCurLine].cch + pStream->paLines[iCurLine].enmEol);
768888227f95954ce8676ae279645fae10e24ba2vboxsync if (offCur < pStream->paLines[iCurLine].cch)
768888227f95954ce8676ae279645fae10e24ba2vboxsync *pcchLine -= offCur;
768888227f95954ce8676ae279645fae10e24ba2vboxsync else
768888227f95954ce8676ae279645fae10e24ba2vboxsync *pcchLine = 0;
768888227f95954ce8676ae279645fae10e24ba2vboxsync pszLine += offCur;
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync }
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync return pszLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync/**
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * Get the current buffer pointer.
b20cc298c1a3191a4e6ce780c19313117902675dvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @returns Buffer pointer on success, NULL on failure (asserted).
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pStream The stream. Must be in read mode.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsyncconst char *ScmStreamGetCur(PSCMSTREAM pStream)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync{
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(!pStream->fWriteOrRead, NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return pStream->pch + pStream->off;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/**
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * Gets a character from the stream.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync *
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @returns The next unsigned character in the stream.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * ~(unsigned)0 on failure.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @param pStream The stream. Must be in read mode.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncunsigned ScmStreamGetCh(PSCMSTREAM pStream)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Check stream state. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync AssertReturn(!pStream->fWriteOrRead, ~(unsigned)0);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_FAILURE(pStream->rc))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return ~(unsigned)0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_UNLIKELY(!pStream->fFullyLineated))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int rc = scmStreamLineate(pStream);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_FAILURE(rc))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return ~(unsigned)0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* If there isn't enough stream left, fail already. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_UNLIKELY(pStream->off >= pStream->cb))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return ~(unsigned)0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Read a character. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync char ch = pStream->pch[pStream->off++];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Advance the line indicator. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync size_t iLine = pStream->iLine;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (pStream->off >= pStream->paLines[iLine].off + pStream->paLines[iLine].cch + pStream->paLines[iLine].enmEol)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync pStream->iLine++;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return (unsigned)ch;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/**
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * Peeks at the next character from the stream.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync *
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @returns The next unsigned character in the stream.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * ~(unsigned)0 on failure.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @param pStream The stream. Must be in read mode.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncunsigned ScmStreamPeekCh(PSCMSTREAM pStream)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Check stream state. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync AssertReturn(!pStream->fWriteOrRead, ~(unsigned)0);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_FAILURE(pStream->rc))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return ~(unsigned)0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_UNLIKELY(!pStream->fFullyLineated))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int rc = scmStreamLineate(pStream);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_FAILURE(rc))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return ~(unsigned)0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* If there isn't enough stream left, fail already. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_UNLIKELY(pStream->off >= pStream->cb))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return ~(unsigned)0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Peek at the next character. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync char ch = pStream->pch[pStream->off];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return (unsigned)ch;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Reads @a cbToRead bytes into @a pvBuf.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Will fail if end of stream is encountered before the entire read has been
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * completed.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @retval VERR_EOF if there isn't @a cbToRead bytes left to read. Stream
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * position will be unchanged.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pvBuf The buffer to read into.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cbToRead The number of bytes to read.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamRead(PSCMSTREAM pStream, void *pvBuf, size_t cbToRead)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(!pStream->fWriteOrRead, VERR_PERMISSION_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* If there isn't enough stream left, fail already. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_UNLIKELY(pStream->cb - pStream->off < cbToRead))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_EOF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Copy the data and simply seek to the new stream position. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync memcpy(pvBuf, &pStream->pch[pStream->off], cbToRead);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return ScmStreamSeekAbsolute(pStream, pStream->off + cbToRead);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Checks if the given line is empty or full of white space.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns true if white space only, false if not (or if non-existant).
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param iLine The line in question.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncbool ScmStreamIsWhiteLine(PSCMSTREAM pStream, size_t iLine)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync SCMEOL enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchLine = ScmStreamGetLineByNo(pStream, iLine, &cchLine, &enmEol);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pchLine)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync while (cchLine && RT_C_IS_SPACE(*pchLine))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pchLine++, cchLine--;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return cchLine == 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Try figure out the end of line style of the give stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns Most likely end of line style.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncSCMEOL ScmStreamGetEol(PSCMSTREAM pStream)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync SCMEOL enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pStream->cLines > 0)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = pStream->paLines[0].enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else if (pStream->cb == 0)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_NONE;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchLF = (const char *)memchr(pStream->pch, '\n', pStream->cb);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pchLF && pchLF != pStream->pch && pchLF[-1] == '\r')
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_CRLF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_LF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (enmEol == SCMEOL_NONE)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_CRLF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_LF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Get the end of line indicator type for a line.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns The EOL indicator. If the line isn't found, the default EOL
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * indicator is return.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param iLine The line (0-base).
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncSCMEOL ScmStreamGetEolByLine(PSCMSTREAM pStream, size_t iLine)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync SCMEOL enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (iLine < pStream->cLines)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = pStream->paLines[iLine].enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_CRLF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync enmEol = SCMEOL_LF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Appends a line to the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in write mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pchLine Pointer to the line.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cchLine Line length.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param enmEol Which end of line indicator to use.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamPutLine(PSCMSTREAM pStream, const char *pchLine, size_t cchLine, SCMEOL enmEol)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Make sure the previous line has a new-line indicator.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t off = pStream->off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t iLine = pStream->iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY( iLine != 0
e99772f9bf09219c532812c859fbeea513c67e65vboxsync && pStream->paLines[iLine - 1].enmEol == SCMEOL_NONE))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->paLines[iLine].cch == 0, VERR_INTERNAL_ERROR_3);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync SCMEOL enmEol2 = enmEol != SCMEOL_NONE ? enmEol : ScmStreamGetEol(pStream);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(off + cchLine + enmEol + enmEol2 > pStream->cbAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamGrowBuffer(pStream, cchLine + enmEol + enmEol2);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (enmEol2 == SCMEOL_LF)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off++] = '\n';
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off++] = '\r';
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off++] = '\n';
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine - 1].enmEol = enmEol2;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].off = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cb = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Ensure we've got sufficient buffer space.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(off + cchLine + enmEol > pStream->cbAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamGrowBuffer(pStream, cchLine + enmEol);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Add a line record.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(iLine + 1 >= pStream->cLinesAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamGrowLines(pStream, iLine);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch = off - pStream->paLines[iLine].off + cchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync iLine++;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLines = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Copy the line
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync memcpy(&pStream->pch[off], pchLine, cchLine);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync off += cchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (enmEol == SCMEOL_LF)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off++] = '\n';
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else if (enmEol == SCMEOL_CRLF)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off++] = '\r';
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off++] = '\n';
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cb = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Start a new line.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].off = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = SCMEOL_NONE;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Writes to the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in write mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pchBuf What to write.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cchBuf How much to write.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamWrite(PSCMSTREAM pStream, const char *pchBuf, size_t cchBuf)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Ensure we've got sufficient buffer space.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t off = pStream->off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(off + cchBuf > pStream->cbAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamGrowBuffer(pStream, cchBuf);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Deal with the odd case where we've already pushed a line with SCMEOL_NONE.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t iLine = pStream->iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY( iLine > 0
e99772f9bf09219c532812c859fbeea513c67e65vboxsync && pStream->paLines[iLine - 1].enmEol == SCMEOL_NONE))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync iLine--;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLines = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Deal with lines.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchLF = (const char *)memchr(pchBuf, '\n', cchBuf);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pchLF)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch += cchBuf;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchLine = pchBuf;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (;;)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_UNLIKELY(iLine + 1 >= pStream->cLinesAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = scmStreamGrowLines(pStream, iLine);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync iLine = pStream->iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch = off - pStream->paLines[iLine].off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = SCMEOL_NONE;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cchLine = pchLF - pchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if ( cchLine
e99772f9bf09219c532812c859fbeea513c67e65vboxsync ? pchLF[-1] != '\r'
e99772f9bf09219c532812c859fbeea513c67e65vboxsync : !pStream->paLines[iLine].cch
e99772f9bf09219c532812c859fbeea513c67e65vboxsync || pStream->pch[pStream->paLines[iLine].off + pStream->paLines[iLine].cch - 1] != '\r')
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = SCMEOL_LF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = SCMEOL_CRLF;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync cchLine--;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch += cchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync iLine++;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t offBuf = pchLF + 1 - pchBuf;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].off = off + offBuf;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].enmEol = SCMEOL_NONE;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cchLeft = cchBuf - offBuf;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync pchLine = pchLF + 1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync pchLF = (const char *)memchr(pchLine, '\n', cchLeft);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pchLF)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[iLine].cch = cchLeft;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->iLine = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cLines = iLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Copy the data and update position and size.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync memcpy(&pStream->pch[off], pchBuf, cchBuf);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync off += cchBuf;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->cb = off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Write a character to the stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pStream The stream. Must be in write mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pchBuf What to write.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cchBuf How much to write.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamPutCh(PSCMSTREAM pStream, char ch)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pStream->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pStream->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Only deal with the simple cases here, use ScmStreamWrite for the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * annoying stuff.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t off = pStream->off;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if ( ch == '\n'
e99772f9bf09219c532812c859fbeea513c67e65vboxsync || RT_UNLIKELY(off + 1 > pStream->cbAllocated))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return ScmStreamWrite(pStream, &ch, 1);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Just append it.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->pch[off] = ch;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->off = off + 1;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pStream->paLines[pStream->iLine].cch++;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync/**
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * Formats a string and writes it to the SCM stream.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @returns The number of bytes written (>= 0). Negative value are IPRT error
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * status codes.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pStream The stream to write to.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pszFormat The format string.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param va The arguments to format.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsyncssize_t ScmStreamPrintfV(PSCMSTREAM pStream, const char *pszFormat, va_list va)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync{
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync char *psz;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync ssize_t cch = RTStrAPrintfV(&psz, pszFormat, va);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync if (cch)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync {
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync int rc = ScmStreamWrite(pStream, psz, cch);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync RTStrFree(psz);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync if (RT_FAILURE(rc))
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync cch = rc;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync }
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return cch;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync}
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync/**
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * Formats a string and writes it to the SCM stream.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @returns The number of bytes written (>= 0). Negative value are IPRT error
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * status codes.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pStream The stream to write to.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pszFormat The format string.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param ... The arguments to format.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsyncssize_t ScmStreamPrintf(PSCMSTREAM pStream, const char *pszFormat, ...)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync{
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync va_list va;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync va_start(va, pszFormat);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync ssize_t cch = ScmStreamPrintfV(pStream, pszFormat, va);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync va_end(va);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return cch;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync}
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Copies @a cLines from the @a pSrc stream onto the @a pDst stream.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * The stream positions will be used and changed in both streams.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns IPRT status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pDst The destination stream. Must be in write mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cLines The number of lines. (0 is accepted.)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pSrc The source stream. Must be in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncint ScmStreamCopyLines(PSCMSTREAM pDst, PSCMSTREAM pSrc, size_t cLines)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pDst->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pDst->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pDst->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(!pSrc->fWriteOrRead, VERR_ACCESS_DENIED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(pSrc->rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pSrc->rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync while (cLines-- > 0)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync SCMEOL enmEol;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync size_t cchLine;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *pchLine = ScmStreamGetLine(pSrc, &cchLine, &enmEol);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!pchLine)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return pDst->rc = (RT_FAILURE(pSrc->rc) ? pSrc->rc : VERR_EOF);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = ScmStreamPutLine(pDst, pchLine, cchLine, enmEol);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync/**
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * If the given C word is at off - 1, return @c true and skip beyond it,
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * otherwise return @c false.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @retval true if the given C-word is at the current position minus one char.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * The stream position changes.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @retval false if not. The stream position is unchanged.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pStream The stream.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param cchWord The length of the word.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pszWord The word.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsyncbool ScmStreamCMatchingWordM1(PSCMSTREAM pStream, const char *pszWord, size_t cchWord)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync{
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Check stream state. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(!pStream->fWriteOrRead, false);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(RT_SUCCESS(pStream->rc), false);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(pStream->fFullyLineated, false);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Sufficient chars left on the line? */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t const iLine = pStream->iLine;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(pStream->off > pStream->paLines[iLine].off, false);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - (pStream->off - 1);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync if (cchWord > cchLeft)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return false;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Do they match? */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync const char *psz = &pStream->pch[pStream->off - 1];
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync if (memcmp(psz, pszWord, cchWord))
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return false;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Is it the end of a C word? */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync if (cchWord < cchLeft)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync {
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync psz += cchWord;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync if (RT_C_IS_ALNUM(*psz) || *psz == '_')
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return false;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync }
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Skip ahead. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync pStream->off += cchWord - 1;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return true;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync}
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync/**
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * Get's the C word starting at the current position.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @returns Pointer to the word on success and the stream position advanced to
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * the end of it.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * NULL on failure, stream position normally unchanged.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pStream The stream to get the C word from.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pcchWord Where to return the word length.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsyncconst char *ScmStreamCGetWord(PSCMSTREAM pStream, size_t *pcchWord)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync{
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Check stream state. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(!pStream->fWriteOrRead, NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(RT_SUCCESS(pStream->rc), NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(pStream->fFullyLineated, NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Get the number of chars left on the line and locate the current char. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t const iLine = pStream->iLine;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - pStream->off;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync const char *psz = &pStream->pch[pStream->off];
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Is it a leading C character. */
8014d9e85803119a55d697b5b802d73c011d1f53vboxsync if (!RT_C_IS_ALPHA(*psz) && *psz != '_')
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return NULL;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Find the end of the word. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync char ch;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t off = 1;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync while ( off < cchLeft
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync && ( (ch = psz[off]) == '_'
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync || RT_C_IS_ALNUM(ch)))
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync off++;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync pStream->off += off;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *pcchWord = off;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return psz;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync}
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync/**
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * Get's the C word starting at the current position minus one.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @returns Pointer to the word on success and the stream position advanced to
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * the end of it.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * NULL on failure, stream position normally unchanged.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pStream The stream to get the C word from.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync * @param pcchWord Where to return the word length.
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsyncconst char *ScmStreamCGetWordM1(PSCMSTREAM pStream, size_t *pcchWord)
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync{
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Check stream state. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(!pStream->fWriteOrRead, NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(RT_SUCCESS(pStream->rc), NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync AssertReturn(pStream->fFullyLineated, NULL);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Get the number of chars left on the line and locate the current char. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t const iLine = pStream->iLine;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - (pStream->off - 1);
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync const char *psz = &pStream->pch[pStream->off - 1];
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Is it a leading C character. */
8014d9e85803119a55d697b5b802d73c011d1f53vboxsync if (!RT_C_IS_ALPHA(*psz) && *psz != '_')
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return NULL;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync /* Find the end of the word. */
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync char ch;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync size_t off = 1;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync while ( off < cchLeft
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync && ( (ch = psz[off]) == '_'
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync || RT_C_IS_ALNUM(ch)))
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync off++;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync pStream->off += off - 1;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync *pcchWord = off;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync return psz;
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync}
b07b4216b07447c916723417ee9b44f69c2fc11fvboxsync