work save: use SimpleIni.h to read/save project
This commit is contained in:
parent
702124bdb0
commit
276c56e270
|
@ -0,0 +1,539 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2004 Unicode, Inc.
|
||||||
|
*
|
||||||
|
* Disclaimer
|
||||||
|
*
|
||||||
|
* This source code is provided as is by Unicode, Inc. No claims are
|
||||||
|
* made as to fitness for any particular purpose. No warranties of any
|
||||||
|
* kind are expressed or implied. The recipient agrees to determine
|
||||||
|
* applicability of information provided. If this file has been
|
||||||
|
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||||
|
* sole remedy for any claim will be exchange of defective media
|
||||||
|
* within 90 days of receipt.
|
||||||
|
*
|
||||||
|
* Limitations on Rights to Redistribute This Code
|
||||||
|
*
|
||||||
|
* Unicode, Inc. hereby grants the right to freely use the information
|
||||||
|
* supplied in this file in the creation of products supporting the
|
||||||
|
* Unicode Standard, and to make copies of this file in any form
|
||||||
|
* for internal or external distribution as long as this notice
|
||||||
|
* remains attached.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||||
|
Author: Mark E. Davis, 1994.
|
||||||
|
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||||
|
Sept 2001: fixed const & error conditions per
|
||||||
|
mods suggested by S. Parent & A. Lillich.
|
||||||
|
June 2002: Tim Dodd added detection and handling of incomplete
|
||||||
|
source sequences, enhanced error detection, added casts
|
||||||
|
to eliminate compiler warnings.
|
||||||
|
July 2003: slight mods to back out aggressive FFFE detection.
|
||||||
|
Jan 2004: updated switches in from-UTF8 conversions.
|
||||||
|
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
|
||||||
|
|
||||||
|
See the header file "ConvertUTF.h" for complete documentation.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
#include "ConvertUTF.h"
|
||||||
|
#ifdef CVTUTF_DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const int halfShift = 10; /* used for shifting by 10 bits */
|
||||||
|
|
||||||
|
static const UTF32 halfBase = 0x0010000UL;
|
||||||
|
static const UTF32 halfMask = 0x3FFUL;
|
||||||
|
|
||||||
|
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||||
|
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||||
|
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||||
|
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF32toUTF16 (
|
||||||
|
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||||
|
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||||
|
ConversionResult result = conversionOK;
|
||||||
|
const UTF32* source = *sourceStart;
|
||||||
|
UTF16* target = *targetStart;
|
||||||
|
while (source < sourceEnd) {
|
||||||
|
UTF32 ch;
|
||||||
|
if (target >= targetEnd) {
|
||||||
|
result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
ch = *source++;
|
||||||
|
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||||
|
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
|
||||||
|
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||||
|
if (flags == strictConversion) {
|
||||||
|
--source; /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*target++ = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*target++ = (UTF16)ch; /* normal case */
|
||||||
|
}
|
||||||
|
} else if (ch > UNI_MAX_LEGAL_UTF32) {
|
||||||
|
if (flags == strictConversion) {
|
||||||
|
result = sourceIllegal;
|
||||||
|
} else {
|
||||||
|
*target++ = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||||
|
if (target + 1 >= targetEnd) {
|
||||||
|
--source; /* Back up source pointer! */
|
||||||
|
result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
ch -= halfBase;
|
||||||
|
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||||
|
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*sourceStart = source;
|
||||||
|
*targetStart = target;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF16toUTF32 (
|
||||||
|
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||||
|
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||||
|
ConversionResult result = conversionOK;
|
||||||
|
const UTF16* source = *sourceStart;
|
||||||
|
UTF32* target = *targetStart;
|
||||||
|
UTF32 ch, ch2;
|
||||||
|
while (source < sourceEnd) {
|
||||||
|
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||||
|
ch = *source++;
|
||||||
|
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||||
|
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||||
|
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||||
|
if (source < sourceEnd) {
|
||||||
|
ch2 = *source;
|
||||||
|
/* If it's a low surrogate, convert to UTF32. */
|
||||||
|
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||||
|
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||||
|
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||||
|
++source;
|
||||||
|
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||||
|
--source; /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||||
|
--source; /* return to the high surrogate */
|
||||||
|
result = sourceExhausted;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (flags == strictConversion) {
|
||||||
|
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||||
|
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||||
|
--source; /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target >= targetEnd) {
|
||||||
|
source = oldSource; /* Back up source pointer! */
|
||||||
|
result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
*target++ = ch;
|
||||||
|
}
|
||||||
|
*sourceStart = source;
|
||||||
|
*targetStart = target;
|
||||||
|
#ifdef CVTUTF_DEBUG
|
||||||
|
if (result == sourceIllegal) {
|
||||||
|
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||||
|
* get the number of trailing bytes that are supposed to follow it.
|
||||||
|
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||||
|
* left as-is for anyone who may want to do such conversion, which was
|
||||||
|
* allowed in earlier algorithms.
|
||||||
|
*/
|
||||||
|
static const char trailingBytesForUTF8[256] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||||
|
* This table contains as many values as there might be trailing bytes
|
||||||
|
* in a UTF-8 sequence.
|
||||||
|
*/
|
||||||
|
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||||
|
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||||
|
* into the first byte, depending on how many bytes follow. There are
|
||||||
|
* as many entries in this table as there are UTF-8 sequence types.
|
||||||
|
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
|
||||||
|
* for *legal* UTF-8 will be 4 or fewer bytes total.
|
||||||
|
*/
|
||||||
|
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||||
|
* Constants have been gathered. Loops & conditionals have been removed as
|
||||||
|
* much as possible for efficiency, in favor of drop-through switches.
|
||||||
|
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||||
|
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||||
|
* into an inline function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF16toUTF8 (
|
||||||
|
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||||
|
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||||
|
ConversionResult result = conversionOK;
|
||||||
|
const UTF16* source = *sourceStart;
|
||||||
|
UTF8* target = *targetStart;
|
||||||
|
while (source < sourceEnd) {
|
||||||
|
UTF32 ch;
|
||||||
|
unsigned short bytesToWrite = 0;
|
||||||
|
const UTF32 byteMask = 0xBF;
|
||||||
|
const UTF32 byteMark = 0x80;
|
||||||
|
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||||
|
ch = *source++;
|
||||||
|
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||||
|
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||||
|
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||||
|
if (source < sourceEnd) {
|
||||||
|
UTF32 ch2 = *source;
|
||||||
|
/* If it's a low surrogate, convert to UTF32. */
|
||||||
|
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||||
|
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||||
|
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||||
|
++source;
|
||||||
|
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||||
|
--source; /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||||
|
--source; /* return to the high surrogate */
|
||||||
|
result = sourceExhausted;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (flags == strictConversion) {
|
||||||
|
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||||
|
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||||
|
--source; /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Figure out how many bytes the result will require */
|
||||||
|
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||||
|
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||||
|
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||||
|
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
|
||||||
|
} else { bytesToWrite = 3;
|
||||||
|
ch = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
target += bytesToWrite;
|
||||||
|
if (target > targetEnd) {
|
||||||
|
source = oldSource; /* Back up source pointer! */
|
||||||
|
target -= bytesToWrite; result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
switch (bytesToWrite) { /* note: everything falls through. */
|
||||||
|
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||||
|
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||||
|
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||||
|
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
|
||||||
|
}
|
||||||
|
target += bytesToWrite;
|
||||||
|
}
|
||||||
|
*sourceStart = source;
|
||||||
|
*targetStart = target;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||||
|
* This must be called with the length pre-determined by the first byte.
|
||||||
|
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||||
|
* length = trailingBytesForUTF8[*source]+1;
|
||||||
|
* and the sequence is illegal right away if there aren't that many bytes
|
||||||
|
* available.
|
||||||
|
* If presented with a length > 4, this returns false. The Unicode
|
||||||
|
* definition of UTF-8 goes up to 4-byte sequences.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||||
|
UTF8 a;
|
||||||
|
const UTF8 *srcptr = source+length;
|
||||||
|
switch (length) {
|
||||||
|
default: return false;
|
||||||
|
/* Everything else falls through when "true"... */
|
||||||
|
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||||
|
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||||
|
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
|
||||||
|
|
||||||
|
switch (*source) {
|
||||||
|
/* no fall-through in this inner switch */
|
||||||
|
case 0xE0: if (a < 0xA0) return false; break;
|
||||||
|
case 0xED: if (a > 0x9F) return false; break;
|
||||||
|
case 0xF0: if (a < 0x90) return false; break;
|
||||||
|
case 0xF4: if (a > 0x8F) return false; break;
|
||||||
|
default: if (a < 0x80) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||||
|
}
|
||||||
|
if (*source > 0xF4) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||||
|
* This is not used here; it's just exported.
|
||||||
|
*/
|
||||||
|
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||||
|
int length = trailingBytesForUTF8[*source]+1;
|
||||||
|
if (source+length > sourceEnd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isLegalUTF8(source, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF8toUTF16 (
|
||||||
|
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||||
|
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||||
|
ConversionResult result = conversionOK;
|
||||||
|
const UTF8* source = *sourceStart;
|
||||||
|
UTF16* target = *targetStart;
|
||||||
|
while (source < sourceEnd) {
|
||||||
|
UTF32 ch = 0;
|
||||||
|
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||||
|
if (source + extraBytesToRead >= sourceEnd) {
|
||||||
|
result = sourceExhausted; break;
|
||||||
|
}
|
||||||
|
/* Do this check whether lenient or strict */
|
||||||
|
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The cases all fall through. See "Note A" below.
|
||||||
|
*/
|
||||||
|
switch (extraBytesToRead) {
|
||||||
|
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||||
|
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||||
|
case 3: ch += *source++; ch <<= 6;
|
||||||
|
case 2: ch += *source++; ch <<= 6;
|
||||||
|
case 1: ch += *source++; ch <<= 6;
|
||||||
|
case 0: ch += *source++;
|
||||||
|
}
|
||||||
|
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||||
|
|
||||||
|
if (target >= targetEnd) {
|
||||||
|
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||||
|
result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||||
|
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||||
|
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||||
|
if (flags == strictConversion) {
|
||||||
|
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*target++ = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*target++ = (UTF16)ch; /* normal case */
|
||||||
|
}
|
||||||
|
} else if (ch > UNI_MAX_UTF16) {
|
||||||
|
if (flags == strictConversion) {
|
||||||
|
result = sourceIllegal;
|
||||||
|
source -= (extraBytesToRead+1); /* return to the start */
|
||||||
|
break; /* Bail out; shouldn't continue */
|
||||||
|
} else {
|
||||||
|
*target++ = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||||
|
if (target + 1 >= targetEnd) {
|
||||||
|
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||||
|
result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
ch -= halfBase;
|
||||||
|
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||||
|
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*sourceStart = source;
|
||||||
|
*targetStart = target;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF32toUTF8 (
|
||||||
|
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||||
|
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||||
|
ConversionResult result = conversionOK;
|
||||||
|
const UTF32* source = *sourceStart;
|
||||||
|
UTF8* target = *targetStart;
|
||||||
|
while (source < sourceEnd) {
|
||||||
|
UTF32 ch;
|
||||||
|
unsigned short bytesToWrite = 0;
|
||||||
|
const UTF32 byteMask = 0xBF;
|
||||||
|
const UTF32 byteMark = 0x80;
|
||||||
|
ch = *source++;
|
||||||
|
if (flags == strictConversion ) {
|
||||||
|
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||||
|
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||||
|
--source; /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Figure out how many bytes the result will require. Turn any
|
||||||
|
* illegally large UTF32 things (> Plane 17) into replacement chars.
|
||||||
|
*/
|
||||||
|
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||||
|
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||||
|
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||||
|
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
|
||||||
|
} else { bytesToWrite = 3;
|
||||||
|
ch = UNI_REPLACEMENT_CHAR;
|
||||||
|
result = sourceIllegal;
|
||||||
|
}
|
||||||
|
|
||||||
|
target += bytesToWrite;
|
||||||
|
if (target > targetEnd) {
|
||||||
|
--source; /* Back up source pointer! */
|
||||||
|
target -= bytesToWrite; result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
switch (bytesToWrite) { /* note: everything falls through. */
|
||||||
|
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||||
|
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||||
|
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||||
|
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
|
||||||
|
}
|
||||||
|
target += bytesToWrite;
|
||||||
|
}
|
||||||
|
*sourceStart = source;
|
||||||
|
*targetStart = target;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF8toUTF32 (
|
||||||
|
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||||
|
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||||
|
ConversionResult result = conversionOK;
|
||||||
|
const UTF8* source = *sourceStart;
|
||||||
|
UTF32* target = *targetStart;
|
||||||
|
while (source < sourceEnd) {
|
||||||
|
UTF32 ch = 0;
|
||||||
|
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||||
|
if (source + extraBytesToRead >= sourceEnd) {
|
||||||
|
result = sourceExhausted; break;
|
||||||
|
}
|
||||||
|
/* Do this check whether lenient or strict */
|
||||||
|
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The cases all fall through. See "Note A" below.
|
||||||
|
*/
|
||||||
|
switch (extraBytesToRead) {
|
||||||
|
case 5: ch += *source++; ch <<= 6;
|
||||||
|
case 4: ch += *source++; ch <<= 6;
|
||||||
|
case 3: ch += *source++; ch <<= 6;
|
||||||
|
case 2: ch += *source++; ch <<= 6;
|
||||||
|
case 1: ch += *source++; ch <<= 6;
|
||||||
|
case 0: ch += *source++;
|
||||||
|
}
|
||||||
|
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||||
|
|
||||||
|
if (target >= targetEnd) {
|
||||||
|
source -= (extraBytesToRead+1); /* Back up the source pointer! */
|
||||||
|
result = targetExhausted; break;
|
||||||
|
}
|
||||||
|
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||||
|
/*
|
||||||
|
* UTF-16 surrogate values are illegal in UTF-32, and anything
|
||||||
|
* over Plane 17 (> 0x10FFFF) is illegal.
|
||||||
|
*/
|
||||||
|
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||||
|
if (flags == strictConversion) {
|
||||||
|
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||||
|
result = sourceIllegal;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*target++ = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*target++ = ch;
|
||||||
|
}
|
||||||
|
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
|
||||||
|
result = sourceIllegal;
|
||||||
|
*target++ = UNI_REPLACEMENT_CHAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*sourceStart = source;
|
||||||
|
*targetStart = target;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Note A.
|
||||||
|
The fall-through switches in UTF-8 reading code save a
|
||||||
|
temp variable, some decrements & conditionals. The switches
|
||||||
|
are equivalent to the following loop:
|
||||||
|
{
|
||||||
|
int tmpBytesToRead = extraBytesToRead+1;
|
||||||
|
do {
|
||||||
|
ch += *source++;
|
||||||
|
--tmpBytesToRead;
|
||||||
|
if (tmpBytesToRead) ch <<= 6;
|
||||||
|
} while (tmpBytesToRead > 0);
|
||||||
|
}
|
||||||
|
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||||
|
similarly unrolled loops.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------- */
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2004 Unicode, Inc.
|
||||||
|
*
|
||||||
|
* Disclaimer
|
||||||
|
*
|
||||||
|
* This source code is provided as is by Unicode, Inc. No claims are
|
||||||
|
* made as to fitness for any particular purpose. No warranties of any
|
||||||
|
* kind are expressed or implied. The recipient agrees to determine
|
||||||
|
* applicability of information provided. If this file has been
|
||||||
|
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||||
|
* sole remedy for any claim will be exchange of defective media
|
||||||
|
* within 90 days of receipt.
|
||||||
|
*
|
||||||
|
* Limitations on Rights to Redistribute This Code
|
||||||
|
*
|
||||||
|
* Unicode, Inc. hereby grants the right to freely use the information
|
||||||
|
* supplied in this file in the creation of products supporting the
|
||||||
|
* Unicode Standard, and to make copies of this file in any form
|
||||||
|
* for internal or external distribution as long as this notice
|
||||||
|
* remains attached.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||||
|
|
||||||
|
Several funtions are included here, forming a complete set of
|
||||||
|
conversions between the three formats. UTF-7 is not included
|
||||||
|
here, but is handled in a separate source file.
|
||||||
|
|
||||||
|
Each of these routines takes pointers to input buffers and output
|
||||||
|
buffers. The input buffers are const.
|
||||||
|
|
||||||
|
Each routine converts the text between *sourceStart and sourceEnd,
|
||||||
|
putting the result into the buffer between *targetStart and
|
||||||
|
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||||
|
*(sourceEnd - 1) is the last item.
|
||||||
|
|
||||||
|
The return result indicates whether the conversion was successful,
|
||||||
|
and if not, whether the problem was in the source or target buffers.
|
||||||
|
(Only the first encountered problem is indicated.)
|
||||||
|
|
||||||
|
After the conversion, *sourceStart and *targetStart are both
|
||||||
|
updated to point to the end of last text successfully converted in
|
||||||
|
the respective buffers.
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
sourceStart - pointer to a pointer to the source buffer.
|
||||||
|
The contents of this are modified on return so that
|
||||||
|
it points at the next thing to be converted.
|
||||||
|
targetStart - similarly, pointer to pointer to the target buffer.
|
||||||
|
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||||
|
two buffers, for overflow checking only.
|
||||||
|
|
||||||
|
These conversion functions take a ConversionFlags argument. When this
|
||||||
|
flag is set to strict, both irregular sequences and isolated surrogates
|
||||||
|
will cause an error. When the flag is set to lenient, both irregular
|
||||||
|
sequences and isolated surrogates are converted.
|
||||||
|
|
||||||
|
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||||
|
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||||
|
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||||
|
must check for illegal sequences.
|
||||||
|
|
||||||
|
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||||
|
to the replacement character; otherwise (when the flag is set to strict)
|
||||||
|
they constitute an error.
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
The value "sourceIllegal" is returned from some routines if the input
|
||||||
|
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||||
|
value will point to the illegal value that caused the problem. E.g.,
|
||||||
|
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||||
|
malformed sequence.
|
||||||
|
|
||||||
|
Author: Mark E. Davis, 1994.
|
||||||
|
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||||
|
Fixes & updates, Sept 2001.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
The following 4 definitions are compiler-specific.
|
||||||
|
The C standard does not guarantee that wchar_t has at least
|
||||||
|
16 bits, so wchar_t is no less portable than unsigned short!
|
||||||
|
All should be unsigned values to avoid sign extension during
|
||||||
|
bit mask & shift operations.
|
||||||
|
------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
typedef unsigned int UTF32; /* at least 32 bits */
|
||||||
|
typedef unsigned short UTF16; /* at least 16 bits */
|
||||||
|
typedef unsigned char UTF8; /* typically 8 bits */
|
||||||
|
typedef unsigned char Boolean; /* 0 or 1 */
|
||||||
|
|
||||||
|
/* Some fundamental constants */
|
||||||
|
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||||
|
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||||
|
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||||
|
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||||
|
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
conversionOK, /* conversion successful */
|
||||||
|
sourceExhausted, /* partial character in source, but hit end */
|
||||||
|
targetExhausted, /* insuff. room in target for conversion */
|
||||||
|
sourceIllegal /* source sequence is illegal/malformed */
|
||||||
|
} ConversionResult;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
strictConversion = 0,
|
||||||
|
lenientConversion
|
||||||
|
} ConversionFlags;
|
||||||
|
|
||||||
|
/* This is for C++ and does no harm in C */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF8toUTF16 (
|
||||||
|
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||||
|
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF16toUTF8 (
|
||||||
|
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||||
|
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF8toUTF32 (
|
||||||
|
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||||
|
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF32toUTF8 (
|
||||||
|
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||||
|
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF16toUTF32 (
|
||||||
|
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||||
|
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||||
|
|
||||||
|
ConversionResult ConvertUTF32toUTF16 (
|
||||||
|
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||||
|
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||||
|
|
||||||
|
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
|
@ -13,6 +13,7 @@ QMAKE_CXXFLAGS_DEBUG += -Werror=return-type
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
ConvertUTF.c \
|
||||||
HighlighterManager.cpp \
|
HighlighterManager.cpp \
|
||||||
autolinkmanager.cpp \
|
autolinkmanager.cpp \
|
||||||
caretlist.cpp \
|
caretlist.cpp \
|
||||||
|
@ -92,8 +93,9 @@ SOURCES += \
|
||||||
widgets/searchresultview.cpp
|
widgets/searchresultview.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
ini.h \
|
ConvertUTF.h \
|
||||||
HighlighterManager.h \
|
HighlighterManager.h \
|
||||||
|
SimpleIni.h \
|
||||||
autolinkmanager.h \
|
autolinkmanager.h \
|
||||||
caretlist.h \
|
caretlist.h \
|
||||||
codeformatter.h \
|
codeformatter.h \
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,761 +0,0 @@
|
||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
* Copyright (c) 2018 Danijel Durakovic
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
* this software and associated documentation files (the "Software"), to deal in
|
|
||||||
* the Software without restriction, including without limitation the rights to
|
|
||||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
* so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// /mINI/ v0.9.10
|
|
||||||
// An INI file reader and writer for the modern age.
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// A tiny utility library for manipulating INI files with a straightforward
|
|
||||||
// API and a minimal footprint. It conforms to the (somewhat) standard INI
|
|
||||||
// format - sections and keys are case insensitive and all leading and
|
|
||||||
// trailing whitespace is ignored. Comments are lines that begin with a
|
|
||||||
// semicolon. Trailing comments are allowed on section lines.
|
|
||||||
//
|
|
||||||
// Files are read on demand, upon which data is kept in memory and the file
|
|
||||||
// is closed. This utility supports lazy writing, which only writes changes
|
|
||||||
// and updates to a file and preserves custom formatting and comments. A lazy
|
|
||||||
// write invoked by a write() call will read the output file, find what
|
|
||||||
// changes have been made and update the file accordingly. If you only need to
|
|
||||||
// generate files, use generate() instead. Section and key order is preserved
|
|
||||||
// on read, write and insert.
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// /* BASIC USAGE EXAMPLE: */
|
|
||||||
//
|
|
||||||
// /* read from file */
|
|
||||||
// mINI::INIFile file("myfile.ini");
|
|
||||||
// mINI::INIStructure ini;
|
|
||||||
// file.read(ini);
|
|
||||||
//
|
|
||||||
// /* read value; gets a reference to actual value in the structure.
|
|
||||||
// if key or section don't exist, a new empty value will be created */
|
|
||||||
// std::string& value = ini["section"]["key"];
|
|
||||||
//
|
|
||||||
// /* read value safely; gets a copy of value in the structure.
|
|
||||||
// does not alter the structure */
|
|
||||||
// std::string value = ini.get("section").get("key");
|
|
||||||
//
|
|
||||||
// /* set or update values */
|
|
||||||
// ini["section"]["key"] = "value";
|
|
||||||
//
|
|
||||||
// /* set multiple values */
|
|
||||||
// ini["section2"].set({
|
|
||||||
// {"key1", "value1"},
|
|
||||||
// {"key2", "value2"}
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// /* write updates back to file, preserving comments and formatting */
|
|
||||||
// file.write(ini);
|
|
||||||
//
|
|
||||||
// /* or generate a file (overwrites the original) */
|
|
||||||
// file.generate(ini);
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Long live the INI file!!!
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef MINI_INI_H_
|
|
||||||
#define MINI_INI_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
namespace mINI
|
|
||||||
{
|
|
||||||
namespace INIStringUtil
|
|
||||||
{
|
|
||||||
const char* const whitespaceDelimiters = " \t\n\r\f\v";
|
|
||||||
inline void trim(std::string& str)
|
|
||||||
{
|
|
||||||
str.erase(str.find_last_not_of(whitespaceDelimiters) + 1);
|
|
||||||
str.erase(0, str.find_first_not_of(whitespaceDelimiters));
|
|
||||||
}
|
|
||||||
#ifndef MINI_CASE_SENSITIVE
|
|
||||||
inline void toLower(std::string& str)
|
|
||||||
{
|
|
||||||
std::transform(str.begin(), str.end(), str.begin(), [](const char c) {
|
|
||||||
return static_cast<const char>(std::tolower(c));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
inline void replace(std::string& str, std::string const& a, std::string const& b)
|
|
||||||
{
|
|
||||||
if (!a.empty())
|
|
||||||
{
|
|
||||||
std::size_t pos = 0;
|
|
||||||
while ((pos = str.find(a, pos)) != std::string::npos)
|
|
||||||
{
|
|
||||||
str.replace(pos, a.size(), b);
|
|
||||||
pos += b.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
|
||||||
const char* const endl = "\r\n";
|
|
||||||
#else
|
|
||||||
const char* const endl = "\n";
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class INIMap
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using T_DataIndexMap = std::unordered_map<std::string, std::size_t>;
|
|
||||||
using T_DataItem = std::pair<std::string, T>;
|
|
||||||
using T_DataContainer = std::vector<T_DataItem>;
|
|
||||||
using T_MultiArgs = typename std::vector<std::pair<std::string, T>>;
|
|
||||||
|
|
||||||
T_DataIndexMap dataIndexMap;
|
|
||||||
T_DataContainer data;
|
|
||||||
|
|
||||||
inline std::size_t setEmpty(std::string& key)
|
|
||||||
{
|
|
||||||
std::size_t index = data.size();
|
|
||||||
dataIndexMap[key] = index;
|
|
||||||
data.emplace_back(key, T());
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using const_iterator = typename T_DataContainer::const_iterator;
|
|
||||||
|
|
||||||
INIMap() { }
|
|
||||||
|
|
||||||
INIMap(INIMap const& other)
|
|
||||||
{
|
|
||||||
std::size_t data_size = other.data.size();
|
|
||||||
for (std::size_t i = 0; i < data_size; ++i)
|
|
||||||
{
|
|
||||||
auto const& key = other.data[i].first;
|
|
||||||
auto const& obj = other.data[i].second;
|
|
||||||
data.emplace_back(key, obj);
|
|
||||||
}
|
|
||||||
dataIndexMap = T_DataIndexMap(other.dataIndexMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator[](std::string key)
|
|
||||||
{
|
|
||||||
INIStringUtil::trim(key);
|
|
||||||
#ifndef MINI_CASE_SENSITIVE
|
|
||||||
INIStringUtil::toLower(key);
|
|
||||||
#endif
|
|
||||||
auto it = dataIndexMap.find(key);
|
|
||||||
bool hasIt = (it != dataIndexMap.end());
|
|
||||||
std::size_t index = (hasIt) ? it->second : setEmpty(key);
|
|
||||||
return data[index].second;
|
|
||||||
}
|
|
||||||
T get(std::string key) const
|
|
||||||
{
|
|
||||||
INIStringUtil::trim(key);
|
|
||||||
#ifndef MINI_CASE_SENSITIVE
|
|
||||||
INIStringUtil::toLower(key);
|
|
||||||
#endif
|
|
||||||
auto it = dataIndexMap.find(key);
|
|
||||||
if (it == dataIndexMap.end())
|
|
||||||
{
|
|
||||||
return T();
|
|
||||||
}
|
|
||||||
return T(data[it->second].second);
|
|
||||||
}
|
|
||||||
bool has(std::string key) const
|
|
||||||
{
|
|
||||||
INIStringUtil::trim(key);
|
|
||||||
#ifndef MINI_CASE_SENSITIVE
|
|
||||||
INIStringUtil::toLower(key);
|
|
||||||
#endif
|
|
||||||
return (dataIndexMap.count(key) == 1);
|
|
||||||
}
|
|
||||||
void set(std::string key, T obj)
|
|
||||||
{
|
|
||||||
INIStringUtil::trim(key);
|
|
||||||
#ifndef MINI_CASE_SENSITIVE
|
|
||||||
INIStringUtil::toLower(key);
|
|
||||||
#endif
|
|
||||||
auto it = dataIndexMap.find(key);
|
|
||||||
if (it != dataIndexMap.end())
|
|
||||||
{
|
|
||||||
data[it->second].second = obj;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dataIndexMap[key] = data.size();
|
|
||||||
data.emplace_back(key, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void set(T_MultiArgs const& multiArgs)
|
|
||||||
{
|
|
||||||
for (auto const& it : multiArgs)
|
|
||||||
{
|
|
||||||
auto const& key = it.first;
|
|
||||||
auto const& obj = it.second;
|
|
||||||
set(key, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool remove(std::string key)
|
|
||||||
{
|
|
||||||
INIStringUtil::trim(key);
|
|
||||||
#ifndef MINI_CASE_SENSITIVE
|
|
||||||
INIStringUtil::toLower(key);
|
|
||||||
#endif
|
|
||||||
auto it = dataIndexMap.find(key);
|
|
||||||
if (it != dataIndexMap.end())
|
|
||||||
{
|
|
||||||
std::size_t index = it->second;
|
|
||||||
data.erase(data.begin() + index);
|
|
||||||
dataIndexMap.erase(it);
|
|
||||||
for (auto& it2 : dataIndexMap)
|
|
||||||
{
|
|
||||||
auto& vi = it2.second;
|
|
||||||
if (vi > index)
|
|
||||||
{
|
|
||||||
vi--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
dataIndexMap.clear();
|
|
||||||
}
|
|
||||||
std::size_t size() const
|
|
||||||
{
|
|
||||||
return data.size();
|
|
||||||
}
|
|
||||||
const_iterator begin() const { return data.begin(); }
|
|
||||||
const_iterator end() const { return data.end(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
using INIStructure = INIMap<INIMap<std::string>>;
|
|
||||||
|
|
||||||
namespace INIParser
|
|
||||||
{
|
|
||||||
using T_ParseValues = std::pair<std::string, std::string>;
|
|
||||||
|
|
||||||
enum class PDataType : char
|
|
||||||
{
|
|
||||||
PDATA_NONE,
|
|
||||||
PDATA_COMMENT,
|
|
||||||
PDATA_SECTION,
|
|
||||||
PDATA_KEYVALUE,
|
|
||||||
PDATA_UNKNOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
inline PDataType parseLine(std::string line, T_ParseValues& parseData)
|
|
||||||
{
|
|
||||||
parseData.first.clear();
|
|
||||||
parseData.second.clear();
|
|
||||||
INIStringUtil::trim(line);
|
|
||||||
if (line.empty())
|
|
||||||
{
|
|
||||||
return PDataType::PDATA_NONE;
|
|
||||||
}
|
|
||||||
char firstCharacter = line[0];
|
|
||||||
if (firstCharacter == ';')
|
|
||||||
{
|
|
||||||
return PDataType::PDATA_COMMENT;
|
|
||||||
}
|
|
||||||
if (firstCharacter == '[')
|
|
||||||
{
|
|
||||||
auto commentAt = line.find_first_of(';');
|
|
||||||
if (commentAt != std::string::npos)
|
|
||||||
{
|
|
||||||
line = line.substr(0, commentAt);
|
|
||||||
}
|
|
||||||
auto closingBracketAt = line.find_last_of(']');
|
|
||||||
if (closingBracketAt != std::string::npos)
|
|
||||||
{
|
|
||||||
auto section = line.substr(1, closingBracketAt - 1);
|
|
||||||
INIStringUtil::trim(section);
|
|
||||||
parseData.first = section;
|
|
||||||
return PDataType::PDATA_SECTION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto lineNorm = line;
|
|
||||||
INIStringUtil::replace(lineNorm, "\\=", " ");
|
|
||||||
auto equalsAt = lineNorm.find_first_of('=');
|
|
||||||
if (equalsAt != std::string::npos)
|
|
||||||
{
|
|
||||||
auto key = line.substr(0, equalsAt);
|
|
||||||
INIStringUtil::trim(key);
|
|
||||||
INIStringUtil::replace(key, "\\=", "=");
|
|
||||||
auto value = line.substr(equalsAt + 1);
|
|
||||||
INIStringUtil::trim(value);
|
|
||||||
parseData.first = key;
|
|
||||||
parseData.second = value;
|
|
||||||
return PDataType::PDATA_KEYVALUE;
|
|
||||||
}
|
|
||||||
return PDataType::PDATA_UNKNOWN;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class INIReader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using T_LineData = std::vector<std::string>;
|
|
||||||
using T_LineDataPtr = std::shared_ptr<T_LineData>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::ifstream fileReadStream;
|
|
||||||
T_LineDataPtr lineData;
|
|
||||||
|
|
||||||
T_LineData readFile()
|
|
||||||
{
|
|
||||||
std::string fileContents;
|
|
||||||
fileReadStream.seekg(0, std::ios::end);
|
|
||||||
fileContents.resize(fileReadStream.tellg());
|
|
||||||
fileReadStream.seekg(0, std::ios::beg);
|
|
||||||
std::size_t fileSize = fileContents.size();
|
|
||||||
fileReadStream.read(&fileContents[0], fileSize);
|
|
||||||
fileReadStream.close();
|
|
||||||
T_LineData output;
|
|
||||||
if (fileSize == 0)
|
|
||||||
{
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
std::string buffer;
|
|
||||||
buffer.reserve(50);
|
|
||||||
for (std::size_t i = 0; i < fileSize; ++i)
|
|
||||||
{
|
|
||||||
char& c = fileContents[i];
|
|
||||||
if (c == '\n')
|
|
||||||
{
|
|
||||||
output.emplace_back(buffer);
|
|
||||||
buffer.clear();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c != '\0' && c != '\r')
|
|
||||||
{
|
|
||||||
buffer += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output.emplace_back(buffer);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INIReader(std::string const& filename, bool keepLineData = false)
|
|
||||||
{
|
|
||||||
fileReadStream.open(filename, std::ios::in | std::ios::binary);
|
|
||||||
if (keepLineData)
|
|
||||||
{
|
|
||||||
lineData = std::make_shared<T_LineData>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~INIReader() { }
|
|
||||||
|
|
||||||
bool operator>>(INIStructure& data)
|
|
||||||
{
|
|
||||||
if (!fileReadStream.is_open())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
T_LineData fileLines = readFile();
|
|
||||||
std::string section;
|
|
||||||
bool inSection = false;
|
|
||||||
INIParser::T_ParseValues parseData;
|
|
||||||
for (auto const& line : fileLines)
|
|
||||||
{
|
|
||||||
auto parseResult = INIParser::parseLine(line, parseData);
|
|
||||||
if (parseResult == INIParser::PDataType::PDATA_SECTION)
|
|
||||||
{
|
|
||||||
inSection = true;
|
|
||||||
data[section = parseData.first];
|
|
||||||
}
|
|
||||||
else if (inSection && parseResult == INIParser::PDataType::PDATA_KEYVALUE)
|
|
||||||
{
|
|
||||||
auto const& key = parseData.first;
|
|
||||||
auto const& value = parseData.second;
|
|
||||||
data[section][key] = value;
|
|
||||||
}
|
|
||||||
if (lineData && parseResult != INIParser::PDataType::PDATA_UNKNOWN)
|
|
||||||
{
|
|
||||||
if (parseResult == INIParser::PDataType::PDATA_KEYVALUE && !inSection)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
lineData->emplace_back(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
T_LineDataPtr getLines()
|
|
||||||
{
|
|
||||||
return lineData;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class INIGenerator
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::ofstream fileWriteStream;
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool prettyPrint = false;
|
|
||||||
|
|
||||||
INIGenerator(std::string const& filename)
|
|
||||||
{
|
|
||||||
fileWriteStream.open(filename, std::ios::out | std::ios::binary);
|
|
||||||
}
|
|
||||||
~INIGenerator() { }
|
|
||||||
|
|
||||||
bool operator<<(INIStructure const& data)
|
|
||||||
{
|
|
||||||
if (!fileWriteStream.is_open())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!data.size())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto it = data.begin();
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
auto const& section = it->first;
|
|
||||||
auto const& collection = it->second;
|
|
||||||
fileWriteStream
|
|
||||||
<< "["
|
|
||||||
<< section
|
|
||||||
<< "]";
|
|
||||||
if (collection.size())
|
|
||||||
{
|
|
||||||
fileWriteStream << INIStringUtil::endl;
|
|
||||||
auto it2 = collection.begin();
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
auto key = it2->first;
|
|
||||||
INIStringUtil::replace(key, "=", "\\=");
|
|
||||||
auto value = it2->second;
|
|
||||||
INIStringUtil::trim(value);
|
|
||||||
fileWriteStream
|
|
||||||
<< key
|
|
||||||
<< ((prettyPrint) ? " = " : "=")
|
|
||||||
<< value;
|
|
||||||
if (++it2 == collection.end())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileWriteStream << INIStringUtil::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (++it == data.end())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileWriteStream << INIStringUtil::endl;
|
|
||||||
if (prettyPrint)
|
|
||||||
{
|
|
||||||
fileWriteStream << INIStringUtil::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class INIWriter
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using T_LineData = std::vector<std::string>;
|
|
||||||
using T_LineDataPtr = std::shared_ptr<T_LineData>;
|
|
||||||
|
|
||||||
std::string filename;
|
|
||||||
|
|
||||||
T_LineData getLazyOutput(T_LineDataPtr const& lineData, INIStructure& data, INIStructure& original)
|
|
||||||
{
|
|
||||||
T_LineData output;
|
|
||||||
INIParser::T_ParseValues parseData;
|
|
||||||
std::string sectionCurrent;
|
|
||||||
bool parsingSection = false;
|
|
||||||
bool continueToNextSection = false;
|
|
||||||
bool discardNextEmpty = false;
|
|
||||||
bool writeNewKeys = false;
|
|
||||||
std::size_t lastKeyLine = 0;
|
|
||||||
for (auto line = lineData->begin(); line != lineData->end(); ++line)
|
|
||||||
{
|
|
||||||
if (!writeNewKeys)
|
|
||||||
{
|
|
||||||
auto parseResult = INIParser::parseLine(*line, parseData);
|
|
||||||
if (parseResult == INIParser::PDataType::PDATA_SECTION)
|
|
||||||
{
|
|
||||||
if (parsingSection)
|
|
||||||
{
|
|
||||||
writeNewKeys = true;
|
|
||||||
parsingSection = false;
|
|
||||||
--line;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sectionCurrent = parseData.first;
|
|
||||||
if (data.has(sectionCurrent))
|
|
||||||
{
|
|
||||||
parsingSection = true;
|
|
||||||
continueToNextSection = false;
|
|
||||||
discardNextEmpty = false;
|
|
||||||
output.emplace_back(*line);
|
|
||||||
lastKeyLine = output.size();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continueToNextSection = true;
|
|
||||||
discardNextEmpty = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parseResult == INIParser::PDataType::PDATA_KEYVALUE)
|
|
||||||
{
|
|
||||||
if (continueToNextSection)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (data.has(sectionCurrent))
|
|
||||||
{
|
|
||||||
auto& collection = data[sectionCurrent];
|
|
||||||
auto const& key = parseData.first;
|
|
||||||
auto const& value = parseData.second;
|
|
||||||
if (collection.has(key))
|
|
||||||
{
|
|
||||||
auto outputValue = collection[key];
|
|
||||||
if (value == outputValue)
|
|
||||||
{
|
|
||||||
output.emplace_back(*line);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
INIStringUtil::trim(outputValue);
|
|
||||||
auto lineNorm = *line;
|
|
||||||
INIStringUtil::replace(lineNorm, "\\=", " ");
|
|
||||||
auto equalsAt = lineNorm.find_first_of('=');
|
|
||||||
auto valueAt = lineNorm.find_first_not_of(
|
|
||||||
INIStringUtil::whitespaceDelimiters,
|
|
||||||
equalsAt + 1
|
|
||||||
);
|
|
||||||
std::string outputLine = line->substr(0, valueAt);
|
|
||||||
if (prettyPrint && equalsAt + 1 == valueAt)
|
|
||||||
{
|
|
||||||
outputLine += " ";
|
|
||||||
}
|
|
||||||
outputLine += outputValue;
|
|
||||||
output.emplace_back(outputLine);
|
|
||||||
}
|
|
||||||
lastKeyLine = output.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (discardNextEmpty && line->empty())
|
|
||||||
{
|
|
||||||
discardNextEmpty = false;
|
|
||||||
}
|
|
||||||
else if (parseResult != INIParser::PDataType::PDATA_UNKNOWN)
|
|
||||||
{
|
|
||||||
output.emplace_back(*line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (writeNewKeys || std::next(line) == lineData->end())
|
|
||||||
{
|
|
||||||
T_LineData linesToAdd;
|
|
||||||
if (data.has(sectionCurrent) && original.has(sectionCurrent))
|
|
||||||
{
|
|
||||||
auto const& collection = data[sectionCurrent];
|
|
||||||
auto const& collectionOriginal = original[sectionCurrent];
|
|
||||||
for (auto const& it : collection)
|
|
||||||
{
|
|
||||||
auto key = it.first;
|
|
||||||
if (collectionOriginal.has(key))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto value = it.second;
|
|
||||||
INIStringUtil::replace(key, "=", "\\=");
|
|
||||||
INIStringUtil::trim(value);
|
|
||||||
linesToAdd.emplace_back(
|
|
||||||
key + ((prettyPrint) ? " = " : "=") + value
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!linesToAdd.empty())
|
|
||||||
{
|
|
||||||
output.insert(
|
|
||||||
output.begin() + lastKeyLine,
|
|
||||||
linesToAdd.begin(),
|
|
||||||
linesToAdd.end()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (writeNewKeys)
|
|
||||||
{
|
|
||||||
writeNewKeys = false;
|
|
||||||
--line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto const& it : data)
|
|
||||||
{
|
|
||||||
auto const& section = it.first;
|
|
||||||
if (original.has(section))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (prettyPrint && output.size() > 0 && !output.back().empty())
|
|
||||||
{
|
|
||||||
output.emplace_back();
|
|
||||||
}
|
|
||||||
output.emplace_back("[" + section + "]");
|
|
||||||
auto const& collection = it.second;
|
|
||||||
for (auto const& it2 : collection)
|
|
||||||
{
|
|
||||||
auto key = it2.first;
|
|
||||||
auto value = it2.second;
|
|
||||||
INIStringUtil::replace(key, "=", "\\=");
|
|
||||||
INIStringUtil::trim(value);
|
|
||||||
output.emplace_back(
|
|
||||||
key + ((prettyPrint) ? " = " : "=") + value
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool prettyPrint = false;
|
|
||||||
|
|
||||||
INIWriter(std::string const& filename)
|
|
||||||
: filename(filename)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~INIWriter() { }
|
|
||||||
|
|
||||||
bool operator<<(INIStructure& data)
|
|
||||||
{
|
|
||||||
struct stat buf;
|
|
||||||
bool fileExists = (stat(filename.c_str(), &buf) == 0);
|
|
||||||
if (!fileExists)
|
|
||||||
{
|
|
||||||
INIGenerator generator(filename);
|
|
||||||
generator.prettyPrint = prettyPrint;
|
|
||||||
return generator << data;
|
|
||||||
}
|
|
||||||
INIStructure originalData;
|
|
||||||
T_LineDataPtr lineData;
|
|
||||||
bool readSuccess = false;
|
|
||||||
{
|
|
||||||
INIReader reader(filename, true);
|
|
||||||
if ((readSuccess = reader >> originalData))
|
|
||||||
{
|
|
||||||
lineData = reader.getLines();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!readSuccess)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
T_LineData output = getLazyOutput(lineData, data, originalData);
|
|
||||||
std::ofstream fileWriteStream(filename, std::ios::out | std::ios::binary);
|
|
||||||
if (fileWriteStream.is_open())
|
|
||||||
{
|
|
||||||
if (output.size())
|
|
||||||
{
|
|
||||||
auto line = output.begin();
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
fileWriteStream << *line;
|
|
||||||
if (++line == output.end())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileWriteStream << INIStringUtil::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class INIFile
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::string filename;
|
|
||||||
|
|
||||||
public:
|
|
||||||
INIFile(std::string const& filename)
|
|
||||||
: filename(filename)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~INIFile() { }
|
|
||||||
|
|
||||||
bool read(INIStructure& data) const
|
|
||||||
{
|
|
||||||
if (data.size())
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
}
|
|
||||||
if (filename.empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
INIReader reader(filename);
|
|
||||||
return reader >> data;
|
|
||||||
}
|
|
||||||
bool generate(INIStructure const& data, bool pretty = false) const
|
|
||||||
{
|
|
||||||
if (filename.empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
INIGenerator generator(filename);
|
|
||||||
generator.prettyPrint = pretty;
|
|
||||||
return generator << data;
|
|
||||||
}
|
|
||||||
bool write(INIStructure& data, bool pretty = false) const
|
|
||||||
{
|
|
||||||
if (filename.empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
INIWriter writer(filename);
|
|
||||||
writer.prettyPrint = pretty;
|
|
||||||
return writer << data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MINI_INI_H_
|
|
|
@ -15,14 +15,12 @@
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include "SimpleIni.h"
|
||||||
Project::Project(const QString &filename, const QString &name, QObject *parent) :
|
Project::Project(const QString &filename, const QString &name, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
mModel(this)
|
mModel(this)
|
||||||
{
|
{
|
||||||
mFilename = filename;
|
mFilename = filename;
|
||||||
mIniFile = std::make_shared<QSettings>(filename,QSettings::IniFormat);
|
|
||||||
mIniFile->setIniCodec(QTextCodec::codecForName(getDefaultSystemEncoding()));
|
|
||||||
mParser = std::make_shared<CppParser>();
|
mParser = std::make_shared<CppParser>();
|
||||||
mParser->setOnGetFileStream(
|
mParser->setOnGetFileStream(
|
||||||
std::bind(
|
std::bind(
|
||||||
|
@ -33,10 +31,10 @@ Project::Project(const QString &filename, const QString &name, QObject *parent)
|
||||||
open();
|
open();
|
||||||
else {
|
else {
|
||||||
mName = name;
|
mName = name;
|
||||||
mIniFile->beginGroup("Project");
|
SimpleIni ini;
|
||||||
mIniFile->setValue("filename", mFilename);
|
ini.SetValue("Project","filename", toByteArray(extractRelativePath(directory(),mFilename)));
|
||||||
mIniFile->setValue("name", mName);
|
ini.SetValue("Project","name", toByteArray(mName));
|
||||||
mIniFile->endGroup();
|
ini.SaveFile(mFilename.toLocal8Bit());
|
||||||
mNode = makeProjectNode();
|
mNode = makeProjectNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,21 +113,23 @@ void Project::open()
|
||||||
auto action = finally([this]{
|
auto action = finally([this]{
|
||||||
mModel.endUpdate();
|
mModel.endUpdate();
|
||||||
});
|
});
|
||||||
QFile fileInfo(mFilename);
|
// QFile fileInfo(mFilename);
|
||||||
loadOptions();
|
SimpleIni ini;
|
||||||
|
ini.LoadFile(mFilename.toLocal8Bit());
|
||||||
|
loadOptions(ini);
|
||||||
|
|
||||||
mNode = makeProjectNode();
|
mNode = makeProjectNode();
|
||||||
|
|
||||||
checkProjectFileForUpdate();
|
checkProjectFileForUpdate(ini);
|
||||||
qDebug()<<"ini filename:"<<mIniFile->fileName();
|
int uCount = ini.GetLongValue("Project","UnitCount",0);
|
||||||
int uCount = mIniFile->value("UnitCount",0).toInt();
|
|
||||||
mIniFile->endGroup();
|
|
||||||
//createFolderNodes;
|
//createFolderNodes;
|
||||||
QDir dir(directory());
|
QDir dir(directory());
|
||||||
for (int i=0;i<uCount;i++) {
|
for (int i=0;i<uCount;i++) {
|
||||||
PProjectUnit newUnit = std::make_shared<ProjectUnit>(this);
|
PProjectUnit newUnit = std::make_shared<ProjectUnit>(this);
|
||||||
mIniFile->beginGroup(QString("Unit%1").arg(i+1));
|
QByteArray groupName = toByteArray(QString("Unit%1").arg(i+1));
|
||||||
newUnit->setFileName(dir.absoluteFilePath(mIniFile->value("FileName","").toString()));
|
newUnit->setFileName(
|
||||||
|
dir.absoluteFilePath(
|
||||||
|
fromByteArray(ini.GetValue(groupName,"FileName",""))));
|
||||||
if (!QFileInfo(newUnit->fileName()).exists()) {
|
if (!QFileInfo(newUnit->fileName()).exists()) {
|
||||||
QMessageBox::critical(pMainWindow,
|
QMessageBox::critical(pMainWindow,
|
||||||
tr("File Not Found"),
|
tr("File Not Found"),
|
||||||
|
@ -138,17 +138,20 @@ void Project::open()
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
newUnit->setModified(true);
|
newUnit->setModified(true);
|
||||||
} else {
|
} else {
|
||||||
newUnit->setFolder(mIniFile->value("Folder","").toString());
|
newUnit->setFolder(fromByteArray(ini.GetValue(groupName,"Folder","")));
|
||||||
newUnit->setCompile(mIniFile->value("Compile", true).toBool());
|
newUnit->setCompile(ini.GetBoolValue(groupName,"Compile", true));
|
||||||
newUnit->setCompileCpp(
|
newUnit->setCompileCpp(
|
||||||
mIniFile->value("CompileCpp",mOptions.useGPP).toBool());
|
ini.GetBoolValue(groupName,"CompileCpp",mOptions.useGPP));
|
||||||
|
|
||||||
newUnit->setLink(mIniFile->value("Link", true).toBool());
|
|
||||||
newUnit->setPriority(mIniFile->value("Priority", 1000).toInt());
|
|
||||||
newUnit->setOverrideBuildCmd(mIniFile->value("OverrideBuildCmd", false).toInt());
|
|
||||||
newUnit->setBuildCmd(mIniFile->value("BuildCmd", "").toString());
|
|
||||||
newUnit->setEncoding(mIniFile->value("FileEncoding",ENCODING_SYSTEM_DEFAULT).toByteArray());
|
|
||||||
|
|
||||||
|
newUnit->setLink(ini.GetBoolValue(groupName,"Link", true));
|
||||||
|
newUnit->setPriority(ini.GetLongValue(groupName,"Priority", 1000));
|
||||||
|
newUnit->setOverrideBuildCmd(ini.GetBoolValue(groupName,"OverrideBuildCmd", false));
|
||||||
|
newUnit->setBuildCmd(fromByteArray(ini.GetValue(groupName,"BuildCmd", "")));
|
||||||
|
QByteArray defaultEncoding = ENCODING_SYSTEM_DEFAULT;
|
||||||
|
if (ini.GetBoolValue(groupName,"DetectEncoding",true)){
|
||||||
|
defaultEncoding = ENCODING_AUTO_DETECT;
|
||||||
|
}
|
||||||
|
newUnit->setEncoding(ini.GetValue(groupName, "FileEncoding",defaultEncoding));
|
||||||
newUnit->setEditor(nullptr);
|
newUnit->setEditor(nullptr);
|
||||||
newUnit->setNew(false);
|
newUnit->setNew(false);
|
||||||
newUnit->setParent(this);
|
newUnit->setParent(this);
|
||||||
|
@ -156,7 +159,6 @@ void Project::open()
|
||||||
newUnit->node()->unitIndex = mUnits.count();
|
newUnit->node()->unitIndex = mUnits.count();
|
||||||
mUnits.append(newUnit);
|
mUnits.append(newUnit);
|
||||||
}
|
}
|
||||||
mIniFile->endGroup();
|
|
||||||
}
|
}
|
||||||
rebuildNodes();
|
rebuildNodes();
|
||||||
}
|
}
|
||||||
|
@ -164,13 +166,9 @@ void Project::open()
|
||||||
void Project::setFileName(const QString &value)
|
void Project::setFileName(const QString &value)
|
||||||
{
|
{
|
||||||
if (mFilename!=value) {
|
if (mFilename!=value) {
|
||||||
mIniFile->sync();
|
|
||||||
mIniFile.reset();
|
|
||||||
QFile::rename(mFilename,value);
|
QFile::rename(mFilename,value);
|
||||||
mFilename = value;
|
mFilename = value;
|
||||||
setModified(true);
|
setModified(true);
|
||||||
mIniFile = std::make_shared<QSettings>(mFilename, QSettings::IniFormat);
|
|
||||||
mIniFile->setIniCodec(QTextCodec::codecForName(getDefaultSystemEncoding()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +341,6 @@ bool Project::removeEditor(int index, bool doClose)
|
||||||
}
|
}
|
||||||
|
|
||||||
//if not fUnits.GetItem(index).fNew then
|
//if not fUnits.GetItem(index).fNew then
|
||||||
mIniFile->remove("Unit"+QString("%1").arg(index+1));
|
|
||||||
PFolderNode node = unit->node();
|
PFolderNode node = unit->node();
|
||||||
PFolderNode parent = node->parent.lock();
|
PFolderNode parent = node->parent.lock();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
@ -433,14 +430,16 @@ void Project::saveLayout()
|
||||||
}
|
}
|
||||||
layIni.endGroup();
|
layIni.endGroup();
|
||||||
// remove old data from project file
|
// remove old data from project file
|
||||||
mIniFile->beginGroup(QString("Unit%1").arg(i+1));
|
SimpleIni ini;
|
||||||
mIniFile->remove("Open");
|
ini.LoadFile(mFilename.toLocal8Bit());
|
||||||
mIniFile->remove("Top");
|
QByteArray groupName = toByteArray(QString("Unit%1").arg(i+1));
|
||||||
mIniFile->remove("CursorCol");
|
ini.Delete(groupName,"Open");
|
||||||
mIniFile->remove("CursorRow");
|
ini.Delete(groupName,"Top");
|
||||||
mIniFile->remove("TopLine");
|
ini.Delete(groupName,"CursorCol");
|
||||||
mIniFile->remove("LeftChar");
|
ini.Delete(groupName,"CursorRow");
|
||||||
mIniFile->endGroup();
|
ini.Delete(groupName,"TopLine");
|
||||||
|
ini.Delete(groupName,"LeftChar");
|
||||||
|
ini.SaveFile(mFilename.toLocal8Bit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,13 +453,17 @@ void Project::saveUnitAs(int i, const QString &sFileName)
|
||||||
// }
|
// }
|
||||||
unit->setNew(false);
|
unit->setNew(false);
|
||||||
unit->setFileName(sFileName);
|
unit->setFileName(sFileName);
|
||||||
mIniFile->beginGroup(QString("Unit%1").arg(i+1));
|
SimpleIni ini;
|
||||||
mIniFile->setValue("FileName",
|
ini.LoadFile(mFilename.toLocal8Bit());
|
||||||
extractRelativePath(
|
QByteArray groupName = toByteArray(QString("Unit%1").arg(i+1));
|
||||||
directory(),
|
ini.SetValue(
|
||||||
sFileName));
|
groupName,
|
||||||
mIniFile->endGroup();
|
"FileName",
|
||||||
mIniFile->sync();
|
toByteArray(
|
||||||
|
extractRelativePath(
|
||||||
|
directory(),
|
||||||
|
sFileName)));
|
||||||
|
ini.SaveFile(mFilename.toLocal8Bit());
|
||||||
setModified(true);
|
setModified(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,10 +483,12 @@ void Project::saveUnitLayout(Editor *e, int index)
|
||||||
bool Project::saveUnits()
|
bool Project::saveUnits()
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
SimpleIni ini;
|
||||||
|
ini.LoadFile(mFilename.toLocal8Bit());
|
||||||
for (int idx = 0; idx < mUnits.count(); idx++) {
|
for (int idx = 0; idx < mUnits.count(); idx++) {
|
||||||
PProjectUnit unit = mUnits[idx];
|
PProjectUnit unit = mUnits[idx];
|
||||||
bool rd_only = false;
|
bool rd_only = false;
|
||||||
mIniFile->beginGroup(QString("Unit%1").arg(count+1));
|
QByteArray groupName = toByteArray(QString("Unit%1").arg(count+1));
|
||||||
if (unit->modified() && fileExists(unit->fileName())
|
if (unit->modified() && fileExists(unit->fileName())
|
||||||
&& isReadOnly(unit->fileName())) {
|
&& isReadOnly(unit->fileName())) {
|
||||||
// file is read-only
|
// file is read-only
|
||||||
|
@ -500,37 +505,36 @@ bool Project::saveUnits()
|
||||||
}
|
}
|
||||||
|
|
||||||
// saved new file or an existing file add to project file
|
// saved new file or an existing file add to project file
|
||||||
|
ini.SetValue(
|
||||||
mIniFile->setValue("FileName",
|
groupName,
|
||||||
extractRelativePath(
|
"FileName",
|
||||||
directory(),
|
toByteArray(
|
||||||
unit->fileName()));
|
extractRelativePath(
|
||||||
|
directory(),
|
||||||
|
unit->fileName())));
|
||||||
count++;
|
count++;
|
||||||
switch(getFileType(unit->fileName())) {
|
switch(getFileType(unit->fileName())) {
|
||||||
case FileType::CHeader:
|
case FileType::CHeader:
|
||||||
case FileType::CSource:
|
case FileType::CSource:
|
||||||
case FileType::CppHeader:
|
case FileType::CppHeader:
|
||||||
case FileType::CppSource:
|
case FileType::CppSource:
|
||||||
mIniFile->setValue("CompileCpp", unit->compileCpp());
|
ini.SetBoolValue(groupName,"CompileCpp", unit->compileCpp());
|
||||||
break;
|
break;
|
||||||
case FileType::WindowsResourceSource:
|
case FileType::WindowsResourceSource:
|
||||||
unit->setFolder("Resources");
|
unit->setFolder("Resources");
|
||||||
}
|
}
|
||||||
|
|
||||||
mIniFile->setValue("Folder", unit->folder());
|
ini.SetValue(groupName,"Folder", toByteArray(unit->folder()));
|
||||||
mIniFile->setValue("Compile", unit->compile());
|
ini.SetBoolValue(groupName,"Compile", unit->compile());
|
||||||
mIniFile->setValue("Link", unit->link());
|
ini.SetBoolValue(groupName,"Link", unit->link());
|
||||||
mIniFile->setValue("Priority", unit->priority());
|
ini.SetLongValue(groupName,"Priority", unit->priority());
|
||||||
mIniFile->setValue("OverrideBuildCmd", unit->overrideBuildCmd());
|
ini.SetBoolValue(groupName,"OverrideBuildCmd", unit->overrideBuildCmd());
|
||||||
mIniFile->setValue("BuildCmd", unit->buildCmd());
|
ini.SetValue(groupName,"BuildCmd", toByteArray(unit->buildCmd()));
|
||||||
mIniFile->setValue("DetectEncoding", unit->encoding()==ENCODING_AUTO_DETECT);
|
ini.SetBoolValue(groupName,"DetectEncoding", unit->encoding()==ENCODING_AUTO_DETECT);
|
||||||
mIniFile->setValue("FileEncoding", unit->encoding());
|
ini.SetValue(groupName,"FileEncoding", toByteArray(unit->encoding()));
|
||||||
mIniFile->endGroup();
|
|
||||||
}
|
}
|
||||||
mIniFile->beginGroup("Project");
|
ini.SetLongValue("Project","UnitCount",count);
|
||||||
mIniFile->setValue("UnitCount",count);
|
ini.SaveFile(mFilename.toLocal8Bit());
|
||||||
mIniFile->endGroup();
|
|
||||||
mIniFile->sync();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,79 +572,74 @@ void Project::updateNodeIndexes()
|
||||||
|
|
||||||
void Project::saveOptions()
|
void Project::saveOptions()
|
||||||
{
|
{
|
||||||
mIniFile->beginGroup("Project");
|
SimpleIni ini;
|
||||||
mIniFile->setValue("FileName", extractRelativePath(directory(), mFilename));
|
ini.LoadFile(mFilename.toLocal8Bit());
|
||||||
mIniFile->setValue("Name", mName);
|
ini.SetValue("Project","FileName", toByteArray(extractRelativePath(directory(), mFilename)));
|
||||||
mIniFile->setValue("Type", static_cast<int>(mOptions.type));
|
ini.SetValue("Project","Name", toByteArray(mName));
|
||||||
mIniFile->setValue("Ver", 3); // Is 3 as of Red Panda Dev-C++ 7.0
|
ini.SetLongValue("Project","Type", static_cast<int>(mOptions.type));
|
||||||
mIniFile->setValue("ObjFiles", mOptions.objFiles.join(";"));
|
ini.SetLongValue("Project","Ver", 3); // Is 3 as of Red Panda Dev-C++ 7.0
|
||||||
mIniFile->setValue("Includes", mOptions.includes.join(";"));
|
ini.SetValue("Project","ObjFiles", toByteArray(mOptions.objFiles.join(";")));
|
||||||
mIniFile->setValue("Libs", mOptions.libs.join(";"));
|
ini.SetValue("Project","Includes", toByteArray(mOptions.includes.join(";")));
|
||||||
mIniFile->setValue("PrivateResource", mOptions.privateResource);
|
ini.SetValue("Project","Libs", toByteArray(mOptions.libs.join(";")));
|
||||||
mIniFile->setValue("ResourceIncludes", mOptions.resourceIncludes.join(";"));
|
ini.SetValue("Project","PrivateResource", toByteArray(mOptions.privateResource));
|
||||||
mIniFile->setValue("MakeIncludes", mOptions.makeIncludes.join(";"));
|
ini.SetValue("Project","ResourceIncludes", toByteArray(mOptions.resourceIncludes.join(";")));
|
||||||
mIniFile->setValue("Compiler", mOptions.compilerCmd);
|
ini.SetValue("Project","MakeIncludes", toByteArray(mOptions.makeIncludes.join(";")));
|
||||||
mIniFile->setValue("CppCompiler", mOptions.cppCompilerCmd);
|
ini.SetValue("Project","Compiler", toByteArray(mOptions.compilerCmd));
|
||||||
mIniFile->setValue("Linker", mOptions.linkerCmd);
|
ini.SetValue("Project","CppCompiler", toByteArray(mOptions.cppCompilerCmd));
|
||||||
mIniFile->setValue("IsCpp", mOptions.useGPP);
|
ini.SetValue("Project","Linker", toByteArray(mOptions.linkerCmd));
|
||||||
mIniFile->setValue("Icon", extractRelativePath(directory(), mOptions.icon));
|
ini.SetBoolValue("Project","IsCpp", mOptions.useGPP);
|
||||||
mIniFile->setValue("ExeOutput", mOptions.exeOutput);
|
ini.SetValue("Project","Icon", toByteArray(extractRelativePath(directory(), mOptions.icon)));
|
||||||
mIniFile->setValue("ObjectOutput", mOptions.objectOutput);
|
ini.SetValue("Project","ExeOutput", toByteArray(mOptions.exeOutput));
|
||||||
mIniFile->setValue("LogOutput", mOptions.logOutput);
|
ini.SetValue("Project","ObjectOutput", toByteArray(mOptions.objectOutput));
|
||||||
mIniFile->setValue("LogOutputEnabled", mOptions.logOutputEnabled);
|
ini.SetValue("Project","LogOutput", toByteArray(mOptions.logOutput));
|
||||||
mIniFile->setValue("OverrideOutput", mOptions.overrideOutput);
|
ini.SetBoolValue("Project","LogOutputEnabled", mOptions.logOutputEnabled);
|
||||||
mIniFile->setValue("OverrideOutputName", mOptions.overridenOutput);
|
ini.SetBoolValue("Project","OverrideOutput", mOptions.overrideOutput);
|
||||||
mIniFile->setValue("HostApplication", mOptions.hostApplication);
|
ini.SetValue("Project","OverrideOutputName", toByteArray(mOptions.overridenOutput));
|
||||||
mIniFile->setValue("UseCustomMakefile", mOptions.useCustomMakefile);
|
ini.SetValue("Project","HostApplication", toByteArray(mOptions.hostApplication));
|
||||||
mIniFile->setValue("CustomMakefile", mOptions.customMakefile);
|
ini.SetBoolValue("Project","UseCustomMakefile", mOptions.useCustomMakefile);
|
||||||
mIniFile->setValue("UsePrecompiledHeader", mOptions.usePrecompiledHeader);
|
ini.SetValue("Project","CustomMakefile", toByteArray(mOptions.customMakefile));
|
||||||
mIniFile->setValue("PrecompiledHeader", mOptions.precompiledHeader);
|
ini.SetBoolValue("Project","UsePrecompiledHeader", mOptions.usePrecompiledHeader);
|
||||||
mIniFile->setValue("CommandLine", mOptions.cmdLineArgs);
|
ini.SetValue("Project","PrecompiledHeader", toByteArray(mOptions.precompiledHeader));
|
||||||
mIniFile->setValue("Folders", mFolders.join(";"));
|
ini.SetValue("Project","CommandLine", toByteArray(mOptions.cmdLineArgs));
|
||||||
mIniFile->setValue("IncludeVersionInfo", mOptions.includeVersionInfo);
|
ini.SetValue("Project","Folders", toByteArray(mFolders.join(";")));
|
||||||
mIniFile->setValue("SupportXPThemes", mOptions.supportXPThemes);
|
ini.SetBoolValue("Project","IncludeVersionInfo", mOptions.includeVersionInfo);
|
||||||
mIniFile->setValue("CompilerSet", mOptions.compilerSet);
|
ini.SetBoolValue("Project","SupportXPThemes", mOptions.supportXPThemes);
|
||||||
mIniFile->setValue("CompilerSettings", mOptions.compilerOptions);
|
ini.SetLongValue("Project","CompilerSet", mOptions.compilerSet);
|
||||||
mIniFile->setValue("StaticLink", mOptions.staticLink);
|
ini.SetValue("Project","CompilerSettings", toByteArray(mOptions.compilerOptions));
|
||||||
mIniFile->setValue("AddCharset", mOptions.addCharset);
|
ini.SetBoolValue("Project","StaticLink", mOptions.staticLink);
|
||||||
mIniFile->setValue("Encoding",mOptions.encoding);
|
ini.SetBoolValue("Project","AddCharset", mOptions.addCharset);
|
||||||
|
ini.SetValue("Project","Encoding",toByteArray(mOptions.encoding));
|
||||||
//for Red Panda Dev C++ 6 compatibility
|
//for Red Panda Dev C++ 6 compatibility
|
||||||
mIniFile->setValue("UseUTF8",mOptions.encoding == ENCODING_UTF8);
|
ini.SetBoolValue("Project","UseUTF8",mOptions.encoding == ENCODING_UTF8);
|
||||||
mIniFile->endGroup();
|
|
||||||
|
|
||||||
mIniFile->beginGroup("VersionInfo");
|
ini.SetLongValue("VersionInfo","Major", mOptions.versionInfo.major);
|
||||||
mIniFile->setValue("Major", mOptions.versionInfo.major);
|
ini.SetLongValue("VersionInfo","Minor", mOptions.versionInfo.minor);
|
||||||
|
ini.SetLongValue("VersionInfo","Release", mOptions.versionInfo.release);
|
||||||
|
ini.SetLongValue("VersionInfo","Build", mOptions.versionInfo.build);
|
||||||
|
ini.SetLongValue("VersionInfo","LanguageID", mOptions.versionInfo.languageID);
|
||||||
|
ini.SetLongValue("VersionInfo","CharsetID", mOptions.versionInfo.charsetID);
|
||||||
|
ini.SetValue("VersionInfo","CompanyName", toByteArray(mOptions.versionInfo.companyName));
|
||||||
|
ini.SetValue("VersionInfo","FileVersion", toByteArray(mOptions.versionInfo.fileVersion));
|
||||||
|
ini.SetValue("VersionInfo","FileDescription", toByteArray(mOptions.versionInfo.fileDescription));
|
||||||
|
ini.SetValue("VersionInfo","InternalName", toByteArray(mOptions.versionInfo.internalName));
|
||||||
|
ini.SetValue("VersionInfo","LegalCopyright", toByteArray(mOptions.versionInfo.legalCopyright));
|
||||||
|
ini.SetValue("VersionInfo","LegalTrademarks", toByteArray(mOptions.versionInfo.legalTrademarks));
|
||||||
|
ini.SetValue("VersionInfo","OriginalFilename", toByteArray(mOptions.versionInfo.originalFilename));
|
||||||
|
ini.SetValue("VersionInfo","ProductName", toByteArray(mOptions.versionInfo.productName));
|
||||||
|
ini.SetValue("VersionInfo","ProductVersion", toByteArray(mOptions.versionInfo.productVersion));
|
||||||
|
ini.SetBoolValue("VersionInfo","AutoIncBuildNr", mOptions.versionInfo.autoIncBuildNr);
|
||||||
|
ini.SetBoolValue("VersionInfo","SyncProduct", mOptions.versionInfo.syncProduct);
|
||||||
|
|
||||||
mIniFile->setValue("Minor", mOptions.versionInfo.minor);
|
|
||||||
mIniFile->setValue("Release", mOptions.versionInfo.release);
|
|
||||||
mIniFile->setValue("Build", mOptions.versionInfo.build);
|
|
||||||
mIniFile->setValue("LanguageID", mOptions.versionInfo.languageID);
|
|
||||||
mIniFile->setValue("CharsetID", mOptions.versionInfo.charsetID);
|
|
||||||
mIniFile->setValue("CompanyName", mOptions.versionInfo.companyName);
|
|
||||||
mIniFile->setValue("FileVersion", mOptions.versionInfo.fileVersion);
|
|
||||||
mIniFile->setValue("FileDescription", mOptions.versionInfo.fileDescription);
|
|
||||||
mIniFile->setValue("InternalName", mOptions.versionInfo.internalName);
|
|
||||||
mIniFile->setValue("LegalCopyright", mOptions.versionInfo.legalCopyright);
|
|
||||||
mIniFile->setValue("LegalTrademarks", mOptions.versionInfo.legalTrademarks);
|
|
||||||
mIniFile->setValue("OriginalFilename", mOptions.versionInfo.originalFilename);
|
|
||||||
mIniFile->setValue("ProductName", mOptions.versionInfo.productName);
|
|
||||||
mIniFile->setValue("ProductVersion", mOptions.versionInfo.productVersion);
|
|
||||||
mIniFile->setValue("AutoIncBuildNr", mOptions.versionInfo.autoIncBuildNr);
|
|
||||||
mIniFile->setValue("SyncProduct", mOptions.versionInfo.syncProduct);
|
|
||||||
mIniFile->endGroup();
|
|
||||||
|
|
||||||
//delete outdated dev4 project options
|
//delete outdated dev4 project options
|
||||||
mIniFile->beginGroup("Project");
|
ini.Delete("Project","NoConsole");
|
||||||
mIniFile->remove("NoConsole");
|
ini.Delete("Project","IsDLL");
|
||||||
mIniFile->remove("IsDLL");
|
ini.Delete("Project","ResFiles");
|
||||||
mIniFile->remove("ResFiles");
|
ini.Delete("Project","IncludeDirs");
|
||||||
mIniFile->remove("IncludeDirs");
|
ini.Delete("Project","CompilerOptions");
|
||||||
mIniFile->remove("CompilerOptions");
|
ini.Delete("Project","Use_GPP");
|
||||||
mIniFile->remove("Use_GPP");
|
|
||||||
mIniFile->endGroup();
|
|
||||||
|
|
||||||
mIniFile->sync(); // force flush
|
|
||||||
|
|
||||||
|
ini.SaveFile(mFilename.toLocal8Bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::addFolder(const QString &s)
|
void Project::addFolder(const QString &s)
|
||||||
|
@ -984,44 +983,39 @@ void Project::buildPrivateResource(bool forceSave)
|
||||||
StringsToFile(contents,hFile);
|
StringsToFile(contents,hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::checkProjectFileForUpdate()
|
void Project::checkProjectFileForUpdate(SimpleIni &ini)
|
||||||
{
|
{
|
||||||
bool cnvt = false;
|
bool cnvt = false;
|
||||||
mIniFile->beginGroup("Project");
|
int uCount = ini.GetLongValue("Project","UnitCount", 0);
|
||||||
int uCount = mIniFile->value("UnitCount", 0).toInt();
|
|
||||||
mIniFile->endGroup();
|
|
||||||
// check if using old way to store resources and fix it
|
// check if using old way to store resources and fix it
|
||||||
QString oldRes = mIniFile->value("Resources", "").toString();
|
QString oldRes = QString::fromLocal8Bit(ini.GetValue("Project","Resources", ""));
|
||||||
if (!oldRes.isEmpty()) {
|
if (!oldRes.isEmpty()) {
|
||||||
QFile::copy(mFilename,mFilename+".bak");
|
QFile::copy(mFilename,mFilename+".bak");
|
||||||
QStringList sl;
|
QStringList sl;
|
||||||
sl = oldRes.split(';',Qt::SkipEmptyParts);
|
sl = oldRes.split(';',Qt::SkipEmptyParts);
|
||||||
for (int i=0;i<sl.count();i++){
|
for (int i=0;i<sl.count();i++){
|
||||||
const QString& s = sl[i];
|
const QString& s = sl[i];
|
||||||
mIniFile->beginGroup(QString("Unit%1").arg(uCount+i));
|
QByteArray groupName = toByteArray(QString("Unit%1").arg(uCount+i));
|
||||||
mIniFile->setValue("Filename", s);
|
ini.SetValue(groupName,"Filename", toByteArray(s));
|
||||||
mIniFile->setValue("Folder", "Resources");
|
ini.SetValue(groupName,"Folder", "Resources");
|
||||||
mIniFile->setValue("Compile",true);
|
ini.SetBoolValue(groupName,"Compile",true);
|
||||||
mIniFile->endGroup();
|
|
||||||
}
|
}
|
||||||
mIniFile->beginGroup("Project");
|
ini.SetLongValue("Project","UnitCount",uCount+sl.count());
|
||||||
mIniFile->setValue("UnitCount",uCount+sl.count());
|
QString folders = QString::fromLocal8Bit(ini.GetValue("Project","Folders",""));
|
||||||
QString folders = mIniFile->value("Folders","").toString();
|
|
||||||
if (!folders.isEmpty())
|
if (!folders.isEmpty())
|
||||||
folders += ",Resources";
|
folders += ",Resources";
|
||||||
else
|
else
|
||||||
folders = "Resources";
|
folders = "Resources";
|
||||||
mIniFile->setValue("Folders",folders);
|
ini.SetValue("Project","Folders",toByteArray(folders));
|
||||||
mIniFile->endGroup();
|
cnvt = true;
|
||||||
|
ini.Delete("Project","Resources");
|
||||||
|
ini.Delete("Project","Focused");
|
||||||
|
ini.Delete("Project","Order");
|
||||||
|
ini.Delete("Project","DebugInfo");
|
||||||
|
ini.Delete("Project","ProfileInfo");
|
||||||
|
ini.SaveFile(mFilename.toLocal8Bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
mIniFile->beginGroup("Project");
|
|
||||||
mIniFile->remove("Resources");
|
|
||||||
mIniFile->remove("Focused");
|
|
||||||
mIniFile->remove("Order");
|
|
||||||
mIniFile->remove("DebugInfo");
|
|
||||||
mIniFile->remove("ProfileInfo");
|
|
||||||
|
|
||||||
if (cnvt)
|
if (cnvt)
|
||||||
QMessageBox::information(
|
QMessageBox::information(
|
||||||
pMainWindow,
|
pMainWindow,
|
||||||
|
@ -1188,13 +1182,11 @@ void Project::loadLayout()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::loadOptions()
|
void Project::loadOptions(SimpleIni& ini)
|
||||||
{
|
{
|
||||||
mIniFile->beginGroup("Project");
|
mName = fromByteArray(ini.GetValue("Project","name", ""));
|
||||||
mName = mIniFile->value("name", "").toString();
|
mOptions.icon = fromByteArray(ini.GetValue("Project", "icon", ""));
|
||||||
mOptions.icon = mIniFile->value("icon", "").toString();
|
mOptions.version = ini.GetLongValue("Project", "Ver", 0);
|
||||||
mOptions.version = mIniFile->value("Ver", 0).toInt();
|
|
||||||
mIniFile->endGroup();
|
|
||||||
if (mOptions.version > 0) { // ver > 0 is at least a v5 project
|
if (mOptions.version > 0) { // ver > 0 is at least a v5 project
|
||||||
if (mOptions.version < 2) {
|
if (mOptions.version < 2) {
|
||||||
mOptions.version = 2;
|
mOptions.version = 2;
|
||||||
|
@ -1206,34 +1198,33 @@ void Project::loadOptions()
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
mIniFile->beginGroup("Project");
|
mOptions.type = static_cast<ProjectType>(ini.GetLongValue("Project", "type", 0));
|
||||||
mOptions.type = static_cast<ProjectType>(mIniFile->value("type", 0).toInt());
|
mOptions.compilerCmd = fromByteArray(ini.GetValue("Project", "Compiler", ""));
|
||||||
mOptions.compilerCmd = mIniFile->value("Compiler", "").toString();
|
mOptions.cppCompilerCmd = fromByteArray(ini.GetValue("Project", "CppCompiler", ""));
|
||||||
mOptions.cppCompilerCmd = mIniFile->value("CppCompiler", "").toString();
|
mOptions.linkerCmd = fromByteArray(ini.GetValue("Project", "Linker", ""));
|
||||||
mOptions.linkerCmd = mIniFile->value("Linker", "").toString();
|
mOptions.objFiles = fromByteArray(ini.GetValue("Project", "ObjFiles", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.objFiles = mIniFile->value("ObjFiles", "").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.libs = fromByteArray(ini.GetValue("Project", "Libs", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.libs = mIniFile->value("Libs", "").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.includes = fromByteArray(ini.GetValue("Project", "Includes", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.includes = mIniFile->value("Includes", "").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.privateResource = fromByteArray(ini.GetValue("Project", "PrivateResource", ""));
|
||||||
mOptions.privateResource = mIniFile->value("PrivateResource", "").toString();
|
mOptions.resourceIncludes = fromByteArray(ini.GetValue("Project", "ResourceIncludes", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.resourceIncludes = mIniFile->value("ResourceIncludes", "").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.makeIncludes = fromByteArray(ini.GetValue("Project", "MakeIncludes", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.makeIncludes = mIniFile->value("MakeIncludes","").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.useGPP = ini.GetBoolValue("Project", "IsCpp", false);
|
||||||
mOptions.useGPP = mIniFile->value("IsCpp", false).toBool();
|
mOptions.exeOutput = fromByteArray(ini.GetValue("Project", "ExeOutput", ""));
|
||||||
mOptions.exeOutput = mIniFile->value("ExeOutput", "").toString();
|
mOptions.objectOutput = fromByteArray(ini.GetValue("Project", "ObjectOutput", ""));
|
||||||
mOptions.objectOutput = mIniFile->value("ObjectOutput", "").toString();
|
mOptions.logOutput = fromByteArray(ini.GetValue("Project", "LogOutput", ""));
|
||||||
mOptions.logOutput = mIniFile->value("LogOutput","").toString();
|
mOptions.logOutputEnabled = ini.GetBoolValue("Project", "LogOutputEnabled", false);
|
||||||
mOptions.logOutputEnabled = mIniFile->value("LogOutputEnabled", false).toBool();
|
mOptions.overrideOutput = ini.GetBoolValue("Project", "OverrideOutput", false);
|
||||||
mOptions.overrideOutput = mIniFile->value("OverrideOutput", false).toBool();
|
mOptions.overridenOutput = fromByteArray(ini.GetValue("Project", "OverrideOutputName", ""));
|
||||||
mOptions.overridenOutput = mIniFile->value("OverrideOutputName","").toString();
|
mOptions.hostApplication = fromByteArray(ini.GetValue("Project", "HostApplication", ""));
|
||||||
mOptions.hostApplication = mIniFile->value("HostApplication","").toString();
|
mOptions.useCustomMakefile = ini.GetBoolValue("Project", "UseCustomMakefile", false);
|
||||||
mOptions.useCustomMakefile = mIniFile->value("UseCustomMakefile", false).toBool();
|
mOptions.customMakefile = fromByteArray(ini.GetValue("Project", "CustomMakefile", ""));
|
||||||
mOptions.customMakefile = mIniFile->value("CustomMakefile","").toString();
|
mOptions.usePrecompiledHeader = ini.GetBoolValue("Project", "UsePrecompiledHeader", false);
|
||||||
mOptions.usePrecompiledHeader = mIniFile->value("UsePrecompiledHeader", false).toBool();
|
mOptions.precompiledHeader = fromByteArray(ini.GetValue("Project", "PrecompiledHeader", ""));
|
||||||
mOptions.precompiledHeader = mIniFile->value("PrecompiledHeader","").toString();
|
mOptions.cmdLineArgs = fromByteArray(ini.GetValue("Project", "CommandLine", ""));
|
||||||
mOptions.cmdLineArgs = mIniFile->value("CommandLine","").toString();
|
mFolders = fromByteArray(ini.GetValue("Project", "Folders", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mFolders = mIniFile->value("Folders","").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.includeVersionInfo = ini.GetBoolValue("Project", "IncludeVersionInfo", false);
|
||||||
mOptions.includeVersionInfo = mIniFile->value("IncludeVersionInfo", false).toBool();
|
mOptions.supportXPThemes = ini.GetBoolValue("Project", "SupportXPThemes", false);
|
||||||
mOptions.supportXPThemes = mIniFile->value("SupportXPThemes", false).toBool();
|
mOptions.compilerSet = ini.GetLongValue("Project", "CompilerSet", pSettings->compilerSets().defaultIndex());
|
||||||
mOptions.compilerSet = mIniFile->value("CompilerSet", pSettings->compilerSets().defaultIndex()).toInt();
|
|
||||||
|
|
||||||
if (mOptions.compilerSet >= pSettings->compilerSets().size()
|
if (mOptions.compilerSet >= pSettings->compilerSets().size()
|
||||||
|| mOptions.compilerSet < 0) { // TODO: change from indices to names
|
|| mOptions.compilerSet < 0) { // TODO: change from indices to names
|
||||||
|
@ -1248,60 +1239,56 @@ void Project::loadOptions()
|
||||||
mOptions.compilerSet = pSettings->compilerSets().defaultIndex();
|
mOptions.compilerSet = pSettings->compilerSets().defaultIndex();
|
||||||
setModified(true);
|
setModified(true);
|
||||||
}
|
}
|
||||||
mOptions.compilerOptions = mIniFile->value("CompilerSettings","").toString();
|
mOptions.compilerOptions = fromByteArray(ini.GetValue("Project", "CompilerSettings", ""));
|
||||||
mOptions.staticLink = mIniFile->value("StaticLink", true).toBool();
|
mOptions.staticLink = ini.GetBoolValue("Project", "StaticLink", true);
|
||||||
mOptions.addCharset = mIniFile->value("AddCharset", true).toBool();
|
mOptions.addCharset = ini.GetBoolValue("Project", "AddCharset", true);
|
||||||
bool useUTF8 = mIniFile->value("UseUTF8", false).toBool();
|
bool useUTF8 = ini.GetBoolValue("Project", "UseUTF8", false);
|
||||||
if (useUTF8) {
|
if (useUTF8) {
|
||||||
mOptions.encoding = mIniFile->value("Encoding", ENCODING_SYSTEM_DEFAULT).toString();
|
mOptions.encoding = fromByteArray(ini.GetValue("Project","Encoding", ENCODING_SYSTEM_DEFAULT));
|
||||||
} else {
|
} else {
|
||||||
mOptions.encoding = mIniFile->value("Encoding", ENCODING_UTF8).toString();
|
mOptions.encoding = fromByteArray(ini.GetValue("Project","Encoding", ENCODING_UTF8));
|
||||||
}
|
}
|
||||||
mIniFile->endGroup();
|
|
||||||
|
|
||||||
mIniFile->beginGroup("VersionInfo");
|
mOptions.versionInfo.major = ini.GetLongValue("VersionInfo", "Major", 0);
|
||||||
mOptions.versionInfo.major = mIniFile->value("Major", 0).toInt();
|
mOptions.versionInfo.minor = ini.GetLongValue("VersionInfo", "Minor", 1);
|
||||||
mOptions.versionInfo.minor = mIniFile->value("Minor", 1).toInt();
|
mOptions.versionInfo.release = ini.GetLongValue("VersionInfo", "Release", 1);
|
||||||
mOptions.versionInfo.release = mIniFile->value("Release", 1).toInt();
|
mOptions.versionInfo.build = ini.GetLongValue("VersionInfo", "Build", 1);
|
||||||
mOptions.versionInfo.build = mIniFile->value("Build", 1).toInt();
|
mOptions.versionInfo.languageID = ini.GetLongValue("VersionInfo", "LanguageID", 0x0409);
|
||||||
mOptions.versionInfo.languageID = mIniFile->value("LanguageID", 0x0409).toInt();
|
mOptions.versionInfo.charsetID = ini.GetLongValue("VersionInfo", "CharsetID", 0x04E4);
|
||||||
mOptions.versionInfo.charsetID = mIniFile->value("CharsetID", 0x04E4).toInt();
|
mOptions.versionInfo.companyName = fromByteArray(ini.GetValue("VersionInfo", "CompanyName", ""));
|
||||||
mOptions.versionInfo.companyName = mIniFile->value("CompanyName","").toString();
|
mOptions.versionInfo.fileVersion = fromByteArray(ini.GetValue("VersionInfo", "FileVersion", "0.1"));
|
||||||
mOptions.versionInfo.fileVersion = mIniFile->value("FileVersion", "0.1").toString();
|
mOptions.versionInfo.fileDescription = fromByteArray(ini.GetValue("VersionInfo", "FileDescription",
|
||||||
mOptions.versionInfo.fileDescription = mIniFile->value("FileDescription",
|
toByteArray(tr("Developed using the Red Panda Dev-C++ IDE"))));
|
||||||
tr("Developed using the Red Panda Dev-C++ IDE")).toString();
|
mOptions.versionInfo.internalName = fromByteArray(ini.GetValue("VersionInfo", "InternalName", ""));
|
||||||
mOptions.versionInfo.internalName = mIniFile->value("InternalName","").toString();
|
mOptions.versionInfo.legalCopyright = fromByteArray(ini.GetValue("VersionInfo", "LegalCopyright", ""));
|
||||||
mOptions.versionInfo.legalCopyright = mIniFile->value("LegalCopyright","").toString();
|
mOptions.versionInfo.legalTrademarks = fromByteArray(ini.GetValue("VersionInfo", "LegalTrademarks", ""));
|
||||||
mOptions.versionInfo.legalTrademarks = mIniFile->value("LegalTrademarks","").toString();
|
mOptions.versionInfo.originalFilename = fromByteArray(ini.GetValue("VersionInfo", "OriginalFilename",
|
||||||
mOptions.versionInfo.originalFilename = mIniFile->value("OriginalFilename",
|
toByteArray(extractFileName(executable()))));
|
||||||
extractFileName(executable())).toString();
|
mOptions.versionInfo.productName = fromByteArray(ini.GetValue("VersionInfo", "ProductName", toByteArray(mName)));
|
||||||
mOptions.versionInfo.productName = mIniFile->value("ProductName", mName).toString();
|
mOptions.versionInfo.productVersion = fromByteArray(ini.GetValue("VersionInfo", "ProductVersion", "0.1.1.1"));
|
||||||
mOptions.versionInfo.productVersion = mIniFile->value("ProductVersion", "0.1.1.1").toString();
|
mOptions.versionInfo.autoIncBuildNr = ini.GetBoolValue("VersionInfo", "AutoIncBuildNr", false);
|
||||||
mOptions.versionInfo.autoIncBuildNr = mIniFile->value("AutoIncBuildNr", false).toBool();
|
mOptions.versionInfo.syncProduct = ini.GetBoolValue("VersionInfo", "SyncProduct", false);
|
||||||
mOptions.versionInfo.syncProduct = mIniFile->value("SyncProduct", false).toBool();
|
|
||||||
mIniFile->endGroup();
|
|
||||||
} else { // dev-c < 4
|
} else { // dev-c < 4
|
||||||
mOptions.version = 2;
|
mOptions.version = 2;
|
||||||
mIniFile->beginGroup("Project");
|
if (!ini.GetBoolValue("VersionInfo", "NoConsole", true))
|
||||||
if (!mIniFile->value("NoConsole", true).toBool())
|
|
||||||
mOptions.type = ProjectType::Console;
|
mOptions.type = ProjectType::Console;
|
||||||
else if (mIniFile->value("IsDLL", false).toBool())
|
else if (ini.GetBoolValue("VersionInfo", "IsDLL", false))
|
||||||
mOptions.type = ProjectType::DynamicLib;
|
mOptions.type = ProjectType::DynamicLib;
|
||||||
else
|
else
|
||||||
mOptions.type = ProjectType::GUI;
|
mOptions.type = ProjectType::GUI;
|
||||||
|
|
||||||
mOptions.privateResource = mIniFile->value("PrivateResource","").toString();
|
mOptions.privateResource = fromByteArray(ini.GetValue("Project", "PrivateResource", ""));
|
||||||
mOptions.resourceIncludes = mIniFile->value("ResourceIncludes","").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.resourceIncludes = fromByteArray(ini.GetValue("Project", "ResourceIncludes", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.objFiles = mIniFile->value("ObjFiles","").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.objFiles = fromByteArray(ini.GetValue("Project", "ObjFiles", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.includes = mIniFile->value("IncludeDirs","").toString().split(";",Qt::SkipEmptyParts);
|
mOptions.includes = fromByteArray(ini.GetValue("Project", "IncludeDirs", "")).split(";",Qt::SkipEmptyParts);
|
||||||
mOptions.compilerCmd = mIniFile->value("CompilerOptions","").toString();
|
mOptions.compilerCmd = fromByteArray(ini.GetValue("Project", "CompilerOptions", ""));
|
||||||
mOptions.useGPP = mIniFile->value("Use_GPP", false).toBool();
|
mOptions.useGPP = ini.GetBoolValue("Project", "Use_GPP", false);
|
||||||
mOptions.exeOutput = mIniFile->value("ExeOutput","").toString();
|
mOptions.exeOutput = fromByteArray(ini.GetValue("Project", "ExeOutput", ""));
|
||||||
mOptions.objectOutput = mIniFile->value("ObjectOutput","").toString();
|
mOptions.objectOutput = fromByteArray(ini.GetValue("Project", "ObjectOutput", ""));
|
||||||
mOptions.overrideOutput = mIniFile->value("OverrideOutput", false).toBool();
|
mOptions.overrideOutput = ini.GetBoolValue("Project", "OverrideOutput", false);
|
||||||
mOptions.overridenOutput = mIniFile->value("OverrideOutputName","").toString();
|
mOptions.overridenOutput = fromByteArray(ini.GetValue("Project", "OverrideOutputName", ""));
|
||||||
mOptions.hostApplication = mIniFile->value("HostApplication","").toString();
|
mOptions.hostApplication = fromByteArray(ini.GetValue("Project", "HostApplication", ""));
|
||||||
mIniFile->endGroup();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,6 +1388,16 @@ void Project::updateFolderNode(PFolderNode node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray Project::toByteArray(const QString &s)
|
||||||
|
{
|
||||||
|
return s.toLocal8Bit();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Project::fromByteArray(const QByteArray &s)
|
||||||
|
{
|
||||||
|
return QString::fromLocal8Bit(s);
|
||||||
|
}
|
||||||
|
|
||||||
const QList<PProjectUnit> &Project::units() const
|
const QList<PProjectUnit> &Project::units() const
|
||||||
{
|
{
|
||||||
return mUnits;
|
return mUnits;
|
||||||
|
@ -1441,16 +1438,6 @@ void Project::setName(const QString &newName)
|
||||||
mName = newName;
|
mName = newName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<QSettings> &Project::iniFile()
|
|
||||||
{
|
|
||||||
return mIniFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Project::setIniFile(const std::shared_ptr<QSettings> &newIniFile)
|
|
||||||
{
|
|
||||||
mIniFile = newIniFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &Project::filename() const
|
const QString &Project::filename() const
|
||||||
{
|
{
|
||||||
return mFilename;
|
return mFilename;
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "SimpleIni.h"
|
||||||
|
|
||||||
|
using SimpleIni = CSimpleIniA;
|
||||||
enum class ProjectType {
|
enum class ProjectType {
|
||||||
GUI=0,
|
GUI=0,
|
||||||
Console=1,
|
Console=1,
|
||||||
|
@ -173,7 +175,7 @@ public:
|
||||||
PFolderNode parentNode,
|
PFolderNode parentNode,
|
||||||
bool rebuild);
|
bool rebuild);
|
||||||
void buildPrivateResource(bool forceSave);
|
void buildPrivateResource(bool forceSave);
|
||||||
void checkProjectFileForUpdate();
|
void checkProjectFileForUpdate(SimpleIni& ini);
|
||||||
void closeUnit(int index);
|
void closeUnit(int index);
|
||||||
void createFolderNodes();
|
void createFolderNodes();
|
||||||
void doAutoOpen();
|
void doAutoOpen();
|
||||||
|
@ -187,7 +189,7 @@ public:
|
||||||
int indexInUnits(const Editor* editor) const;
|
int indexInUnits(const Editor* editor) const;
|
||||||
QString listUnitStr(const QChar& separator);
|
QString listUnitStr(const QChar& separator);
|
||||||
void loadLayout(); // load all [UnitX]
|
void loadLayout(); // load all [UnitX]
|
||||||
void loadOptions();
|
void loadOptions(SimpleIni& ini);
|
||||||
void loadUnitLayout(Editor *e, int index); // load single [UnitX] cursor positions
|
void loadUnitLayout(Editor *e, int index); // load single [UnitX] cursor positions
|
||||||
PFolderNode makeNewFileNode(const QString& s, bool isFolder, PFolderNode newParent);
|
PFolderNode makeNewFileNode(const QString& s, bool isFolder, PFolderNode newParent);
|
||||||
PFolderNode makeProjectNode();
|
PFolderNode makeProjectNode();
|
||||||
|
@ -217,9 +219,6 @@ public:
|
||||||
std::shared_ptr<CppParser> cppParser();
|
std::shared_ptr<CppParser> cppParser();
|
||||||
const QString &filename() const;
|
const QString &filename() const;
|
||||||
|
|
||||||
std::shared_ptr<QSettings> &iniFile();
|
|
||||||
void setIniFile(const std::shared_ptr<QSettings> &newIniFile);
|
|
||||||
|
|
||||||
const QString &name() const;
|
const QString &name() const;
|
||||||
void setName(const QString &newName);
|
void setName(const QString &newName);
|
||||||
|
|
||||||
|
@ -240,10 +239,12 @@ private:
|
||||||
void open();
|
void open();
|
||||||
void removeFolderRecurse(PFolderNode node);
|
void removeFolderRecurse(PFolderNode node);
|
||||||
void updateFolderNode(PFolderNode node);
|
void updateFolderNode(PFolderNode node);
|
||||||
|
QByteArray toByteArray(const QString& s);
|
||||||
|
QString fromByteArray(const QByteArray& s);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<PProjectUnit> mUnits;
|
QList<PProjectUnit> mUnits;
|
||||||
ProjectOptions mOptions;
|
ProjectOptions mOptions;
|
||||||
std::shared_ptr<QSettings> mIniFile;
|
|
||||||
QString mFilename;
|
QString mFilename;
|
||||||
QString mName;
|
QString mName;
|
||||||
bool mModified;
|
bool mModified;
|
||||||
|
|
|
@ -630,9 +630,9 @@ QString extractRelativePath(const QString &base, const QString &dest)
|
||||||
QFileInfo baseInfo(base);
|
QFileInfo baseInfo(base);
|
||||||
QDir baseDir;
|
QDir baseDir;
|
||||||
if (baseInfo.isDir()) {
|
if (baseInfo.isDir()) {
|
||||||
baseDir = baseInfo.absoluteDir();
|
baseDir = QDir(baseInfo.absoluteFilePath());
|
||||||
} else {
|
} else {
|
||||||
baseDir = baseInfo.dir();
|
baseDir = baseInfo.absoluteDir();
|
||||||
}
|
}
|
||||||
return baseDir.relativeFilePath(dest);
|
return baseDir.relativeFilePath(dest);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue