filesplitter.cpp revision eef2e5c5d3dce76f732cc55e434a5e6e85033115
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* $Id$ */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** @file
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * File splitter - Splits a text file according to ###### markers in it.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Copyright (C) 2006-2012 Oracle Corporation
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * available from http://www.virtualbox.org. This file is free software;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * General Public License (GPL) as published by the Free Software
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync* Header Files *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync*******************************************************************************/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <sys/types.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <sys/stat.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <stdio.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <stdlib.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <errno.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/string.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/stdarg.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync* Defined Constants And Macros *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync*******************************************************************************/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef S_ISDIR
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# define S_ISDIR(a_fMode) ( (S_IFMT & (a_fMode)) == S_IFDIR )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Calculates the line number for a file position.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Line number.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszContent The file content.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszPos The current position.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic unsigned long lineNumber(const char *pcszContent, const char *pcszPos)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned long cLine = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while ( *pcszContent
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (uintptr_t)pcszContent < (uintptr_t)pcszPos)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pcszContent = strchr(pcszContent, '\n');
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pcszContent)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync ++cLine;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ++pcszContent;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return cLine;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync/**
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Writes an error message.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns RTEXITCODE_FAILURE.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszFormat Error message.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ... Format argument referenced in the message.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int printErr(const char *pcszFormat, ...)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync va_list va;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fprintf(stderr, "filesplitter: ");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync va_start(va, pcszFormat);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync vfprintf(stderr, pcszFormat, va);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync va_end(va);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTEXITCODE_FAILURE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Opens the makefile list for writing.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Exit code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszPath The path to the file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszVariableName The make variable name.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppFile Where to return the file stream.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int openMakefileList(const char *pcszPath, const char *pcszVariableName, FILE **ppFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *ppFile = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync FILE *pFile= fopen(pcszPath, "w");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Failed to open \"%s\" for writing the file list");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fprintf(pFile, "%s := \\\n", pcszVariableName) <= 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fclose(pFile);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Error writing to the makefile list.\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *ppFile = pFile;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Adds the given file to the makefile list.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Exit code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pFile The file stream of the makefile list.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pszFilename The file name to add.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int addFileToMakefileList(FILE *pFile, char *pszFilename)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char *pszSlash = pszFilename;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while ((pszSlash = strchr(pszSlash, '\\')) != NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pszSlash++ = '/';
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fprintf(pFile, "\t%s \\\n", pszFilename) <= 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Error adding file to makefile list.\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Closes the makefile list.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Exit code derived from @a rc.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pFile The file stream of the makefile list.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param rc The current exit code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int closeMakefileList(FILE *pFile, int rc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fprintf(pFile, "\n\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fclose(pFile))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Error closing the file list file: %s\n", strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Reads in a file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Exit code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszFile The path to the file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppszFile Where to return the buffer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcchFile Where to return the file size.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int readFile(const char *pcszFile, char **ppszFile, size_t *pcchFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync FILE *pFile;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync struct stat FileStat;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (stat(pcszFile, &FileStat))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Failed to stat \"%s\": %s\n", pcszFile, strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pFile = fopen(pcszFile, "r");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Failed to open \"%s\": %s\n", pcszFile, strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *ppszFile = (char *)malloc(FileStat.st_size + 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (*ppszFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync errno = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cbRead = fread(*ppszFile, 1, FileStat.st_size, pFile);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( cbRead <= (size_t)FileStat.st_size
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (cbRead > 0 || !ferror(pFile)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (ftell(pFile) == FileStat.st_size) /* (\r\n vs \n in the DOS world) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (*ppszFile)[cbRead] = '\0';
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pcchFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pcchFile = (size_t)cbRead;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fclose(pFile);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = printErr("Error reading \"%s\": %s\n", pcszFile, strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync free(*ppszFile);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *ppszFile = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = printErr("Failed to allocate %lu bytes\n", (unsigned long)(FileStat.st_size + 1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fclose(pFile);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Checks whether the sub-file already exists and has the exact
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * same content.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true if the existing file matches exactly, otherwise @c false.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszFilename The path to the file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszSubContent The content to write.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cchSubContent The length of the content.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool compareSubFile(const char *pcszFilename, const char *pcszSubContent, size_t cchSubContent)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync struct stat FileStat;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (stat(pcszFilename, &FileStat))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((size_t)FileStat.st_size < cchSubContent)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cchExisting;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char *pszExisting;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = readFile(pcszFilename, &pszExisting, &cchExisting);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fRc = cchExisting == cchSubContent
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && !memcmp(pcszSubContent, pszExisting, cchSubContent);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync free(pszExisting);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return fRc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Writes out a sub-file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns exit code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszFilename The path to the sub-file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszSubContent The content of the file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cchSubContent The size of the content.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int writeSubFile(const char *pcszFilename, const char *pcszSubContent, size_t cchSubContent)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync FILE *pFile = fopen(pcszFilename, "w");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pFile)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Failed to open \"%s\" for writing: %s\n", pcszFilename, strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync errno = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fwrite(pcszSubContent, cchSubContent, 1, pFile) != 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = printErr("Error writing \"%s\": %s\n", pcszFilename, strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync errno = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2 = fclose(pFile);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc2 == EOF)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = printErr("Error closing \"%s\": %s\n", pcszFilename, strerror(errno));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Does the actual file splitting.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns exit code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszOutDir Path to the output directory.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcszContent The content to split up.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pFileList The file stream of the makefile list. Can be NULL.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int splitFile(const char *pcszOutDir, const char *pcszContent, FILE *pFileList)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static char const s_szBeginMarker[] = "\n// ##### BEGINFILE \"";
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static char const s_szEndMarker[] = "\n// ##### ENDFILE";
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const size_t cchBeginMarker = sizeof(s_szBeginMarker) - 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const char *pcszSearch = pcszContent;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t const cchOutDir = strlen(pcszOutDir);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned long cFilesWritten = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned long cFilesUnchanged = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync do
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* find begin marker */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const char *pcszBegin = strstr(pcszSearch, s_szBeginMarker);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pcszBegin)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* find line after begin marker */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const char *pcszLineAfterBegin = strchr(pcszBegin + cchBeginMarker, '\n');
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pcszLineAfterBegin)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("No newline after begin-file marker found.\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ++pcszLineAfterBegin;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* find filename end quote in begin marker line */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const char *pcszStartFilename = pcszBegin + cchBeginMarker;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const char *pcszEndQuote = (const char *)memchr(pcszStartFilename, '\"', pcszLineAfterBegin - pcszStartFilename);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pcszEndQuote)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Can't parse filename after begin-file marker (line %lu).\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync lineNumber(pcszContent, s_szBeginMarker));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* find end marker */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const char *pcszEnd = strstr(pcszLineAfterBegin, s_szEndMarker);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pcszEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("No matching end-line marker for begin-file marker found (line %lu).\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync lineNumber(pcszContent, s_szBeginMarker));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* construct output filename */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cchFilename = pcszEndQuote - pcszStartFilename;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char *pszFilename = (char *)malloc(cchOutDir + 1 + cchFilename + 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pszFilename)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return printErr("Can't allocate memory for filename.\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(pszFilename, pcszOutDir, cchOutDir);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pszFilename[cchOutDir] = '/';
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(pszFilename + cchOutDir + 1, pcszStartFilename, cchFilename);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pszFilename[cchFilename + 1 + cchOutDir] = '\0';
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Write the file only if necessary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (compareSubFile(pszFilename, pcszLineAfterBegin, pcszEnd - pcszLineAfterBegin))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cFilesUnchanged++;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = writeSubFile(pszFilename, pcszLineAfterBegin, pcszEnd - pcszLineAfterBegin);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cFilesWritten++;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (!rc)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = addFileToMakefileList(pFileList, pszFilename);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync free(pszFilename);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pcszSearch = pcszEnd;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync } while (rc == 0 && pcszSearch);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync printf("filesplitter: Out of %lu files: %lu rewritten, %lu unchanged. (%s)\n",
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync cFilesWritten + cFilesUnchanged, cFilesWritten, cFilesUnchanged, pcszOutDir);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncint main(int argc, char *argv[])
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (argc == 3 || argc == 5)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync struct stat DirStat;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if ( stat(argv[2], &DirStat) == 0
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync && S_ISDIR(DirStat.st_mode))
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync char *pszContent;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = readFile(argv[1], &pszContent, NULL);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (!rc)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync FILE *pFileList = NULL;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (argc == 5)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = openMakefileList(argv[3], argv[4], &pFileList);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (argc < 4 || pFileList)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = splitFile(argv[2], pszContent, pFileList);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pFileList)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = closeMakefileList(pFileList, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync free(pszContent);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = printErr("Given argument \"%s\" is not a valid directory.\n", argv[2]);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = printErr("Syntax error: usage: filesplitter <infile> <outdir> [<list.kmk> <kmkvar>]\n");
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync