home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: WPS_PM
/
WPS_PM.zip
/
xfld085s.zip
/
helpers
/
stringh.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-15
|
19KB
|
609 lines
/*
*@@sourcefile stringh.c:
* contains string/text helper functions that are independent
* of a single application, i.e. you can use them in any
* program. These are good for parsing/splitting strings and
* other stuff used throughout XFolder.
*
* Function prefixes (new with V0.81):
* -- strh* string helper functions.
*
*@@include #define INCL_DOSDATETIME
*@@include #include <os2.h>
*@@include #include "stringh.h"
*/
/*
* Copyright (C) 1997-99 Ulrich Möller.
* This file is part of the XFolder source package.
* XFolder is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, in version 2 as it comes in the
* "COPYING" file of the XFolder main distribution.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define INCL_WINSHELLDATA
#include <os2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "stringh.h"
// #define _PMPRINTF_
#include "pmprintf.h"
/*
*@@ strhReplace:
* replace oldStr with newStr in str.
*
* str should have enough allocated space for the replacement, no check
* is made for this. str and OldStr/NewStr should not overlap.
* The empty string ("") is found at the beginning of every string.
*
* Returns: pointer to first location behind where NewStr was inserted
* or NULL if OldStr was not found.
* This is useful for multiple replacements also.
* (be careful not to replace the empty string this way !)
*
* Author: Gilles Kohl
* Started: 09.06.1992 12:16:47
* Modified: 09.06.1992 12:41:41
* Subject: Replace one string by another in a given buffer.
* This code is public domain. Use freely.
*/
char* strhReplace(char* str, char* oldStr, char* newStr)
{
int OldLen, NewLen;
char *p, *q;
if (NULL == (p = strstr(str, oldStr)))
return p;
OldLen = strlen(oldStr);
NewLen = strlen(newStr);
memmove(q = p+NewLen, p+OldLen, strlen(p+OldLen)+1);
memcpy(p, newStr, NewLen);
return (q);
}
/*
*@@ strhInsert:
* inserts to_insert into in_str at position place and
* copies the result to out_str
*
* Author: Gilles Kohl
* Started: 09.06.1992 12:16:47
* Modified: 09.06.1992 12:41:41
* Subject: Replace one string by another in a given buffer.
* This code is public domain. Use freely.
*/
char* strhInsert(char* out_str, char* in_str, char* to_insert, int place)
{
char *out_ptr = out_str, buffer[255], *ptr = buffer;
if (place <= 0)
return ptr;
if ( in_str == out_str )
{
while( -- place )
if ( ! *out_str++ ) return(out_ptr);
while ( *ptr++ = *in_str++ )
; /* strcpy : used if in_str = out_str */
ptr = buffer;
}
else {
while( -- place )
if ( ! (*out_str++ = *in_str++) )
return(out_ptr);
ptr = in_str;
}
while( *out_str++ = *to_insert++ )
;
out_str --;
while ( *out_str++ = *ptr++ )
;
return out_ptr;
}
/*
*@@ strhistr:
* like strstr, but case-insensitive.
*/
PSZ strhistr(PSZ string1, PSZ string2)
{
PSZ prc = NULL;
if ((string1) && (string2)) {
PSZ pszSrchIn = strdup(string1);
PSZ pszSrchFor = strdup(string2);
strupr(pszSrchIn);
strupr(pszSrchFor);
if ((pszSrchIn) && (pszSrchFor)) {
prc = strstr(pszSrchIn, pszSrchFor);
if (prc) {
// prc now has the first occurence of the string,
// but in pszSrchIn; we need to map this
// return value to the original string
prc = (prc-pszSrchIn) // offset in pszSrchIn
+ string1;
}
}
if (pszSrchFor)
free(pszSrchFor);
if (pszSrchIn)
free(pszSrchIn);
}
return (prc);
}
/*
*@@ strhThousandsULong:
* converts a ULONG into a decimal string, while
* inserting thousands separators into it. Specify
* the separator char in cThousands.
* Returns pszTarget so you can use it directly
* with sprintf and the "%s" flag.
* For cThousands, you should use the data in
* OS2.INI ("PM_National" application), which is
* always set according to the "Country" object.
* Use strhThousandsDouble for "double" values.
*/
PSZ strhThousandsULong(PSZ pszTarget, // out: decimal as string
ULONG ul, // in: decimal to convert
CHAR cThousands) // in: separator char (e.g. '.')
{
USHORT ust, uss, usc;
CHAR szTemp[40];
sprintf(szTemp, "%d", ul);
ust = 0;
usc = strlen(szTemp);
for (uss = 0; uss < usc; uss++)
{
if (uss)
if (((usc - uss) % 3) == 0)
{
pszTarget[ust] = cThousands;
ust++;
}
pszTarget[ust] = szTemp[uss];
ust++;
}
pszTarget[ust] = '\0';
return (pszTarget);
}
/*
*@@ strhThousandsDouble:
* like strhThousandsULong, but for a "double"
* value. Note that after-comma values are truncated.
*/
PSZ strhThousandsDouble(PSZ pszTarget, double dbl, CHAR cThousands)
{
USHORT ust, uss, usc;
CHAR szTemp[40];
sprintf(szTemp, "%.0f", floor(dbl));
ust = 0;
usc = strlen(szTemp);
for (uss = 0; uss < usc; uss++)
{
if (uss)
if (((usc - uss) % 3) == 0)
{
pszTarget[ust] = cThousands;
ust++;
}
pszTarget[ust] = szTemp[uss];
ust++;
}
pszTarget[ust] = '\0';
return (pszTarget);
}
/*
*@@ strhFileDate:
* converts file date data to a string (to pszBuf).
* You can pass any FDATE structure to this function,
* which are returned in those FILEFINDBUF* or
* FILESTATUS* structs by the Dos* functions.
* ulDateFormat can be queried using
+ PrfQueryProfileInt(HINI_USER, "PM_National", "iDate", 0);
*
* meaning:
* -- 0 mm.dd.yyyy (English)
* -- 1 dd.mm.yyyy (e.g. German)
* -- 2 yyyy.mm.dd (Japanese)
* -- 3 yyyy.dd.mm
*
* cDateSep is used as a date separator (e.g. '.').
* This can be queried using:
+ PrfQueryProfileString(HINI_USER, "PM_National", "sDate", "/",
+ szDateSep, sizeof(szDateSep)-1);
*/
VOID strhFileDate(PSZ pszBuf, // out: string returned
FDATE* pfDate, // in: date information
ULONG ulDateFormat, // in: date format (0-3)
CHAR cDateSep) // in: date separator (e.g. '.')
{
switch (ulDateFormat) {
case 0: // mm.dd.yyyy (English)
sprintf(pszBuf, "%02d%c%02d%c%04d",
pfDate->month,
cDateSep,
pfDate->day,
cDateSep,
((pfDate->year)+1980));
break;
case 1: // dd.mm.yyyy (e.g. German)
sprintf(pszBuf, "%02d%c%02d%c%04d",
pfDate->day,
cDateSep,
pfDate->month,
cDateSep,
((pfDate->year)+1980));
break;
case 2: // yyyy.mm.dd (Japanese)
sprintf(pszBuf, "%04d%c%02d%c%02d",
((pfDate->year)+1980),
cDateSep,
pfDate->month,
cDateSep,
pfDate->day);
break;
default: // yyyy.dd.mm
sprintf(pszBuf, "%04d%c%02d%c%02d",
((pfDate->year)+1980), cDateSep,
pfDate->day, cDateSep,
pfDate->month);
break;
}
}
/*
*@@ strhFileTime:
* converts file time data to a string (to pszBuf).
* You can pass any FTIME structure to this function,
* which are returned in those FILEFINDBUF* or
* FILESTATUS* structs by the Dos* functions.
* ulTimeFormat can be queried using
+ PrfQueryProfileInt(HINI_USER, "PM_National", "iTime", 0);
* meaning:
* -- 0 12-hour clock
* -- >0 24-hour clock
*
* cDateSep is used as a time separator (e.g. ':').
* This can be queried using:
+ PrfQueryProfileString(HINI_USER, "PM_National", "sTime", ":",
+ szTimeSep, sizeof(szTimeSep)-1);
*
*@@changed 99-03-15 fixed 12-hour crash
*/
VOID strhFileTime(PSZ pszBuf, // out: string returned
FTIME* pfTime, // in: time information
ULONG ulTimeFormat, // in: 24-hour time format (0 or 1)
CHAR cTimeSep) // in: time separator (e.g. ':')
{
if (ulTimeFormat == 0)
{
// for 12-hour clock, we need additional INI data
CHAR szAMPM[10] = "err";
if (pfTime->hours > 12)
{
// > 12h: PM.
// Note: 12:xx noon is 12 AM, not PM (even though
// AM stands for "ante meridiam", but English is just
// not logical), so that's handled below.
PrfQueryProfileString(HINI_USER,
"PM_National",
"s2359", // key
"PM", // default
szAMPM, sizeof(szAMPM)-1);
sprintf(pszBuf, "%02d%c%02d%c%02d %s",
// leave 12 == 12 (not 0)
pfTime->hours % 12,
cTimeSep,
pfTime->minutes,
cTimeSep,
pfTime->twosecs*2,
szAMPM);
} else
{
// <= 12h: AM
PrfQueryProfileString(HINI_USER,
"PM_National",
"s1159", // key
"AM", // default
szAMPM, sizeof(szAMPM)-1);
sprintf(pszBuf, "%02d%c%02d%c%02d %s",
pfTime->hours,
cTimeSep,
pfTime->minutes,
cTimeSep,
pfTime->twosecs*2,
szAMPM);
}
}
else
// 24-hour clock
sprintf(pszBuf, "%02d%c%02d%c%02d",
pfTime->hours, cTimeSep,
pfTime->minutes, cTimeSep,
pfTime->twosecs*2);
}
/*
*@@ strhFindEOL:
* returns a pointer to the next \r, \n or NULL character
* following pszSearchIn. Stores the offset in *pulOffset.
*/
PSZ strhFindEOL(PSZ pszSearchIn, PULONG pulOffset)
{
PSZ p = pszSearchIn;
if (pulOffset)
*pulOffset = 0;
while (TRUE) {
if ( (*p == '\r') || (*p == '\n') || (*p == 0) )
return (p);
p++;
if (pulOffset)
(*pulOffset)++;
}
}
/*
*@@ strhFindKey:
* finds pszKey in pszSearchIn; similar to strhistr,
* but this one makes sure the key is at the beginning
* of a line. Spaces before the key are tolerated.
* Returns NULL if the key was not found.
* Used by strhGetParameter/strhSetParameter; useful
* for analyzing CONFIG.SYS settings.
*/
PSZ strhFindKey(PSZ pszSearchIn, // in: text buffer to search
PSZ pszKey, // in: key to search for
PBOOL pfIsAllUpperCase) // out: TRUE if key is completely in upper case;
// can be NULL if not needed
{
PSZ p = NULL;
BOOL fFound = FALSE;
_Pmpf((" strhFindKey %s", pszKey));
p = pszSearchIn;
do {
p = strhistr(p, pszKey);
_Pmpf((" found @ ofs %d", (p-pszSearchIn) ));
if ((p) && (p >= pszSearchIn)) {
// make sure the key is at the beginning of a line
// by going backwards until we find a char != " "
PSZ p2 = p;
while ( (*p2 == ' ') && (p2 > pszSearchIn) )
p2--;
// if previous char is an EOL sign, go on
if ( (*(p2-1) == '\r')
|| (*(p2-1) == '\n')
|| (p2 == pszSearchIn)
)
{
// found:
fFound = TRUE; // go on, p contains found key
if (pfIsAllUpperCase) {
// test for all upper case
ULONG cbKey = strlen(pszKey),
ul = 0;
*pfIsAllUpperCase = TRUE;
for (ul = 0; ul < cbKey; ul++)
if (islower(*(p+ul))) {
_Pmpf((" Lower case found: %c", *(p+ul)));
*pfIsAllUpperCase = FALSE;
break;
}
}
} // else search next key
else
p++; // search on after this key
}
} while ((!fFound) && (p != NULL) && (p != pszSearchIn));
return (p);
}
/*
*@@ strhGetParameter:
* searches pszSearchIn for the key pszKey; if found, it
* returns a pointer to the following characters in pszSearchIn
* and, if pszCopyTo != NULL, copies the rest of the line to
* that buffer, of which cbCopyTo specified the size.
* If the key is not found, NULL is returned.
* This is useful for querying CONFIG.SYS settings.
* <P><B>Example:</B> this would return "YES" if you searched
* for "PAUSEONERROR", and "PAUSEONERROR=YES" existed in pszSearchIn.
*/
PSZ strhGetParameter(PSZ pszSearchIn, // in: text buffer to search
PSZ pszKey, // in: key to search for
PSZ pszCopyTo, // out: key value
ULONG cbCopyTo) // out: sizeof(*pszCopyTo)
{
PSZ p = strhFindKey(pszSearchIn, pszKey, NULL),
prc = NULL;
// copy to pszCopyTo
if (p) {
prc = p + strlen(pszKey);
if (pszCopyTo) {
ULONG cb;
PSZ pEOL = strhFindEOL(prc, &cb);
if (pEOL) {
_Pmpf(("%s: cb: %d, p2-p1: %d", pszKey, cb, pEOL-prc));
if (cb > cbCopyTo)
cb = cbCopyTo-1;
strncpy(pszCopyTo, prc, cb);
pszCopyTo[cbCopyTo-1] = '\0';
}
}
}
return (prc);
}
/*
*@@ strhSetParameter:
* searches pszSearchIn for the key pszKey; if found, it
* replaces the characters following this key up to the
* end of the line by pszParam. If pszKey is not found in
* pszSearchIn, it is appended to the file in a new line. You
* must ensure that *pszSearchin is large enough for the
* manipulation, i.e. it must be at least of the following
* size:
* strlen(pszSearchIn) + strlen(pszNewParam) + 1
* in case the key was not found and will be appended.
* This function searches w/out case sensitivity.
* Returns a pointer to the new parameter.
*/
PSZ strhSetParameter(PSZ pszSearchIn, // in: text buffer to search
PSZ pszKey, // in: key to search for
PSZ pszNewParam, // in: new parameter to set for key
BOOL fRespectCase) // in: if TRUE, pszNewParam will
// be converted to upper case if the found key is
// in upper case also. pszNewParam should be in
// lower case if you use this.
{
BOOL fIsAllUpperCase = FALSE;
PSZ pKey = strhFindKey(pszSearchIn, pszKey, &fIsAllUpperCase),
prc = NULL;
_Pmpf(("%s, upper case: %d", pszKey, fIsAllUpperCase));
if (pKey) {
// key found in file:
// replace existing parameter
PSZ pOldParam = pKey + strlen(pszKey);
prc = pOldParam;
// pOldParam now has the old parameter, which we
// will overwrite now
// printf(" found %s @ %d\n", pszKey, (pKey-pszSearchIn));
if (pOldParam) {
ULONG cbOldParam;
PSZ pEOL = strhFindEOL(pOldParam, &cbOldParam);
// pEOL now has first end-of-line after the
// parameter
// printf(" old param is @ %d\n", pOldParam-pszSearchIn);
if (pEOL) {
PSZ pszOldCopy = (PSZ)malloc(cbOldParam+1);
strncpy(pszOldCopy, pOldParam, cbOldParam);
pszOldCopy[cbOldParam] = '\0';
// printf(" found EOL @ %d\n", pEOL-pszSearchIn);
if (fIsAllUpperCase)
strupr(pszNewParam);
strhReplace(pOldParam, pszOldCopy, pszNewParam);
free(pszOldCopy);
}
}
} else {
// key not found: append to end of file
strcat(pszSearchIn, "\r\n");
strcat(pszSearchIn, pszKey);
strcat(pszSearchIn, strupr(pszNewParam));
strcat(pszSearchIn, "\r\n");
// printf(" Appended %s%s to end of file\n", pszKey, pszNewParam);
}
return (prc);
}
/*
*@@ strhDeleteLine:
* this deletes the line in pszSearchIn which starts with
* the key pszKey. Returns TRUE if the line was found and
* deleted.
*/
BOOL strhDeleteLine(PSZ pszSearchIn, PSZ pszKey)
{
BOOL fIsAllUpperCase = FALSE;
PSZ pKey = strhFindKey(pszSearchIn, pszKey, &fIsAllUpperCase);
BOOL brc = FALSE;
if (pKey) {
PSZ pEOL = strhFindEOL(pKey, NULL);
// pEOL now has first end-of-line after the key
if (pEOL) {
// delete line by overwriting it with
// the next line
strcpy(pKey, pEOL+2);
} else {
// EOL not found: we must be at the end of the file
*pKey = '\0';
}
brc = TRUE;
}
return (brc);
}
/*
*@@ strhBeautifyTitle:
* replaces all line breaks (0xd, 0xa) with spaces.
*/
BOOL strhBeautifyTitle(PSZ psz)
{
BOOL rc = FALSE;
CHAR *p;
while (p = strchr(psz, 0xa))
{
*p = ' ';
rc = TRUE;
}
while (p = strchr(psz, 0xd))
{
*p = ' ';
rc = TRUE;
}
return (rc);
}