source: trunk/kLdr/kLdrHlp.c@ 2861

Last change on this file since 2861 was 2861, checked in by bird, 19 years ago

Put the PE module interpreter thru the wringer and learnt how much the window file mapping API sucks.

  • Property svn:keywords set to Id
File size: 20.8 KB
Line 
1/* $Id: kLdrHlp.c 2861 2006-11-10 03:04:42Z bird $ */
2/** @file
3 *
4 * kLdr - The Dynamic Loader, Helper Functions.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#ifdef __OS2__
32# define INCL_BASE
33# define INCL_ERRORS
34# include <os2.h>
35#elif defined(__WIN__)
36# include <Windows.h>
37#else
38# error "port me"
39#endif
40
41#include <kLdr.h>
42#include "kLdrHlp.h"
43
44
45/*******************************************************************************
46* Global Variables *
47*******************************************************************************/
48#ifdef __OS2__
49/** The loader sempahore. */
50static HMTX g_hmtx;
51/** The base of the stub object.
52 * The OS/2 exe stub consists of a single data object. When allocating memory
53 * for an executable, we'll have to reuse this. */
54static void *g_pvStub = NULL;
55/** The size of the stub object - 0 if no stub. */
56static size_t g_cbStub = 0;
57
58#elif defined(__WIN__)
59/** The loader sempahore. */
60static CRITICAL_SECTION g_CritSect;
61/** The system info. */
62static SYSTEM_INFO g_SystemInfo;
63#else
64# error "port me"
65#endif
66
67
68/**
69 * Initializes the loader semaphore.
70 *
71 * @returns 0 on success, non-zero OS status code on failure.
72 */
73int kldrHlpSemInit(void)
74{
75#ifdef __OS2__
76 APIRET rc;
77 g_hmtx = NULLHANDLE;
78 rc = DosCreateMutexSem(NULL, &g_hmtx, 0, FALSE);
79 if (rc)
80 return rc;
81
82#elif defined(__WIN__)
83 InitializeCriticalSection(&g_CritSect);
84
85#else
86# error "port me"
87#endif
88 return 0;
89}
90
91
92/**
93 * Terminates the loader semaphore.
94 */
95void kldrHlpSemTerm(void)
96{
97#ifdef __OS2__
98 APIRET rc;
99 HMTX hmtx = g_hmtx;
100 g_hmtx = NULLHANDLE;
101 rc = DosCloseMutexSem(hmtx);
102 if (rc)
103 return rc;
104
105#elif defined(__WIN__)
106 DeleteCriticalSection(&g_CritSect);
107
108#else
109# error "port me"
110#endif
111}
112
113
114/**
115 * Requests the loader sempahore ownership.
116 * This can be done recursivly.
117 *
118 * @returns 0 on success, non-zero OS status code on failure.
119 */
120int kldrHlpSemRequest(void)
121{
122#ifdef __OS2__
123 APIRET rc = DosRequestMutexSem(g_hmtx, 5000);
124 if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT)
125 {
126 unsigned i = 0;
127 do
128 {
129 /** @todo check for deadlocks etc. */
130 rc = DosRequestMutexSem(g_hmtx, 1000);
131 } while ( ( rc == ERROR_TIMEOUT
132 || rc == ERROR_SEM_TIMEOUT
133 || rc == ERROR_INTERRUPT)
134 && i++ < 120);
135 }
136 return rc;
137
138#elif defined(__WIN__)
139 EnterCriticalSection(&g_CritSect);
140 return 0;
141
142#else
143# error "port me"
144#endif
145}
146
147
148/**
149 * Releases the loader semaphore ownership.
150 * The caller is responsible for making sure it's the semaphore owner!
151 */
152void kldrHlpSemRelease(void)
153{
154#ifdef __OS2__
155 APIRET rc = DosReleaseMutexSem(g_hmtx);
156 kldrHlpAssert(!rc); (void)rc;
157
158#elif defined(__WIN__)
159 LeaveCriticalSection(&g_CritSect);
160
161#else
162# error "port me"
163#endif
164
165}
166
167#ifdef __OS2__
168static ULONG kldrHlpPageProtToNative(KLDRPROT enmProt)
169{
170 switch (enmProt)
171 {
172 case KLDRPROT_NOACCESS: return PAG_EXECUTE | PAG_READ | PAG_WRITE;
173 case KLDRPROT_READONLY: return PAG_COMMIT | PAG_READ;
174 case KLDRPROT_READWRITE: return PAG_COMMIT | PAG_READ | PAG_WRITE;
175 case KLDRPROT_EXECUTE: return PAG_COMMIT | PAG_EXECUTE;
176 case KLDRPROT_EXECUTE_READ: return PAG_COMMIT | PAG_EXECUTE | PAG_READ;
177 case KLDRPROT_EXECUTE_READWRITE: return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE;
178 default:
179 kldrHlpAssert(0);
180 return ~0U;
181 }
182}
183#elif defined(__WIN__)
184static DWORD kldrHlpPageProtToNative(KLDRPROT enmProt)
185{
186 switch (enmProt)
187 {
188 case KLDRPROT_NOACCESS: return PAGE_NOACCESS;
189 case KLDRPROT_READONLY: return PAGE_READONLY;
190 case KLDRPROT_READWRITE: return PAGE_READWRITE;
191 case KLDRPROT_EXECUTE: return PAGE_EXECUTE;
192 case KLDRPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
193 case KLDRPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
194 default:
195 kldrHlpAssert(0);
196 return ~0U;
197 }
198}
199#endif
200
201
202/**
203 * Allocate a chunk of memory with page granularity.
204 *
205 * @returns 0 on success, non-zero OS status code on failure.
206 * @param ppv Where to store the address of the allocated memory.
207 * If fFixed is set, *ppv will on entry contain the desired address (page aligned).
208 * @param cb Number of bytes. Page aligned.
209 * @param enmProt The new protection. Copy-on-write is invalid.
210 */
211int kldrHlpPageAlloc(void **ppv, size_t cb, KLDRPROT enmProt, unsigned fFixed)
212{
213#ifdef __OS2__
214 APIRET rc;
215 ULONG fFlags = kldrHlpPageProtToNative(enmProt);;
216
217 if (!fFixed)
218 {
219 /* simple */
220 rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY);
221 if (rc == ERROR_INVALID_PARAMETER)
222 rc = DosAllocMem(ppv, cb, fFlags);
223 }
224 else
225 {
226 /* not so simple. */
227 /** @todo I've got code for this in libc somewhere. */
228 }
229 if (!rc)
230 return 0;
231 kldrHlpAssert(0);
232 return rc;
233
234#elif defined(__WIN__)
235 /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */
236 int rc;
237 DWORD fProt = kldrHlpPageProtToNative(enmProt);
238
239 if (!g_SystemInfo.dwPageSize)
240 GetSystemInfo(&g_SystemInfo);
241
242 *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt);
243 if (*ppv != NULL)
244 return 0;
245 rc = GetLastError();
246 kldrHlpAssert(0);
247 return rc;
248
249#else
250# error "port me"
251#endif
252}
253
254
255/**
256 * Change the protection of one or more pages in an allocation.
257 *
258 * (This will of course only work correctly on memory allocated by kldrHlpPageAlloc().)
259 *
260 * @returns 0 on success, non-zero OS status code on failure.
261 * @param pv First page. Page aligned.
262 * @param cb Number of bytes. Page aligned.
263 * @param enmProt The new protection. Copy-on-write is invalid.
264 */
265int kldrHlpPageProtect(void *pv, size_t cb, KLDRPROT enmProt)
266{
267#ifdef __OS2__
268 APIRET rc;
269 uintptr_t offStub;
270 ULONG fFlags = kldrHlpPageProtToNative(enmProt);;
271
272 /*
273 * The non-stub pages.
274 */
275 rc = DosSetMem(pv, cb, fFlags);
276 if (rc && fFlags != PAG_DECOMMIT)
277 rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT);
278 if (rc)
279 {
280 /* Try page by page. */
281 while (cb > 0)
282 {
283 rc = DosSetMem(pv, 0x1000, fFlags);
284 if (rc && fFlags != PAG_DECOMMIT)
285 rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT);
286 if (rc)
287 return rc;
288 pv = (void *)((uintptr_t)pv + 0x1000);
289 cb -= 0x1000;
290 }
291 }
292 kldrHlpAssert(!rc);
293 return rc;
294
295#elif defined(__WIN__)
296 DWORD fOldProt = 0;
297 DWORD fProt = kldrHlpPageProtToNative(enmProt);
298 int rc = 0;
299
300 if (!VirtualProtect(pv, cb, fProt, &fOldProt))
301 {
302 rc = GetLastError();
303 kldrHlpAssert(0);
304 }
305 return rc;
306#else
307# error "port me"
308#endif
309}
310
311
312/**
313 * Free memory allocated by kldrHlpPageAlloc().
314 *
315 * @returns 0 on success, non-zero OS status code on failure.
316 * @param pv The address returned by kldrHlpPageAlloc().
317 * @param cb The byte count requested from kldrHlpPageAlloc().
318 */
319int kldrHlpPageFree(void *pv, size_t cb)
320{
321#ifdef __OS2__
322 APIRET rc;
323
324 /*
325 * Deal with any portion overlapping with the stub.
326 */
327 uintptr_t offStub = (uintptr_t)pv - (uintptr_t)g_pvStub;
328 if (offStub < g_cbStub)
329 {
330 /* decommit the pages in the stub. */
331 size_t cbSub = KLDR_MIN(g_cbStub - offStub, cb);
332 rc = DosSetMem(pv, cbStub, PAG_DECOMMIT);
333 if (rc)
334 {
335 /* Page by page, ignoring errors after the first success. */
336 while (cbSub > 0)
337 {
338 if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT))
339 rc = 0;
340 pv = (void *)((uintptr_t)pv + 0x1000);
341 cbSub -= 0x1000;
342 cb -= 0x1000;
343 }
344 if (rc)
345 {
346 kldrHlpAssert(!rc);
347 return rc;
348 }
349 }
350 else
351 {
352 cb -= cbSub;
353 if (!cb)
354 return 0;
355 pv = (void *)((uintptr_t)pv + cbSub);
356 }
357 }
358
359 /*
360 * Free the object.
361 */
362 rc = DosFreeMem(pv);
363 kldrHlpAssert(!rc);
364 return rc;
365
366#elif defined(__WIN__)
367 /*
368 * Free the object.
369 */
370 int rc = 0;
371 if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE))
372 {
373 rc = GetLastError();
374 kldrHlpAssert(0);
375 }
376 return rc;
377
378#else
379# error "port me"
380#endif
381}
382
383
384/**
385 * Get an environment variable.
386 *
387 * @returns 0 on success, on failure an OS specific status code is returned.
388 * @param pszVar The variable name.
389 * @param pszVal Where to store the value. NULL is allowed if *pcchVal is 0.
390 * @param pcchVal On input the size of the buffer pointed to by pszVal.
391 * On output this contains the string length on success, while on
392 * failure (including buffer overflow) the require buffer size.
393 * If the variable wasn't found, it's set to 0.
394 */
395int kldrHlpGetEnv(const char *pszVar, char *pszVal, size_t *pcchVal)
396{
397#ifdef __OS2__
398 PSZ pszValue = NULL;
399 int rc = DosScanEnv((PCSZ)pszVar, &pszValue);
400 if (!rc)
401 {
402 size_t cch = kLdrHlpStrLen(pszValue);
403 if (pszVal)
404 {
405 if (*pcchVal > cch)
406 {
407 kLdrHlpMemCopy(pszVal, pszValue, cch + 1);
408 *pcchVal = cch;
409 }
410 else if (*pcchVal)
411 {
412 kLdrHlpMemCopy(pszVal, pszValue, *pcchVal);
413 pszVal[*pcchVal - 1] = '\0';
414 rc = ERROR_BUFFER_OVERFLOW;
415 *pcchVal = cch + 1;
416 }
417 }
418 else
419 {
420 rc = ERROR_BUFFER_OVERFLOW;
421 *pcchVal = cch + 1;
422 }
423 }
424 else
425 {
426 if (pszVal)
427 *pszVal = '\0';
428 *pcchVal = 0;
429 }
430
431 return rc;
432
433#elif defined(__WIN__)
434 DWORD cch;
435 SetLastError(0);
436 cch = GetEnvironmentVariable(pszVar, pszVal, *pcchVal);
437 if (cch)
438 {
439 *pcchVal = cch;
440 return 0;
441 }
442 if (!GetLastError() == ERROR_ENVVAR_NOT_FOUND)
443 {
444 *pcchVal = 0;
445 return ERROR_ENVVAR_NOT_FOUND;
446 }
447 *pcchVal = cch;
448 return ERROR_BUFFER_OVERFLOW;
449
450#else
451# error "Port me"
452#endif
453}
454
455
456/**
457 * Gets an environment variable and converts it to a size_t.
458 *
459 * @returns 0 and *pcb on success.
460 * Some non-zero OS or kLdr status code on failure.
461 * @param pszVar The name of the variable.
462 * @param pcb Where to put the value.
463 */
464int kldrHlpGetEnvUZ(const char *pszVar, size_t *pcb)
465{
466 size_t cb;
467 unsigned uBase;
468 char szVal[64];
469 size_t cchVal = sizeof(szVal);
470 const char *psz;
471 int rc;
472
473 *pcb = 0;
474 rc = kldrHlpGetEnv(pszVar, szVal, &cchVal);
475 if (rc)
476 return rc;
477
478 /* figure out the base. */
479 uBase = 10;
480 psz = szVal;
481 if ( *psz == '0'
482 && (psz[1] == 'x' || psz[1] == 'X'))
483 {
484 uBase = 16;
485 psz += 2;
486 }
487
488 /* convert it up to the first unknown char. */
489 cb = 0;
490 for(;;)
491 {
492 const char ch = *psz;
493 unsigned uDigit;
494 if (!ch)
495 break;
496 else if (ch >= '0' && ch <= '9')
497 uDigit = ch - '0';
498 else if (ch >= 'a' && ch <= 'z')
499 uDigit = ch - 'a' + 10;
500 else if (ch >= 'A' && ch <= 'Z')
501 uDigit = ch - 'A' + 10;
502 else
503 break;
504 if (uDigit >= uBase)
505 break;
506
507 /* add the digit */
508 cb *= uBase;
509 cb += uDigit;
510
511 psz++;
512 }
513
514 /* check for unit */
515 if (*psz == 'm' || *psz == 'M')
516 cb *= 1024*1024;
517 else if (*psz == 'k' ||*psz == 'K')
518 cb *= 1024;
519 else if (*psz == 'g' || *psz == 'G')
520 cb *= 1024*1024*1024;
521
522 *pcb = cb;
523 return 0;
524}
525
526
527/**
528 * Get the pointer to the filename part of the name.
529 *
530 * @returns Pointer to where the filename starts within the string pointed to by pszFilename.
531 * @returns Pointer to the terminator char if no filename.
532 * @param pszFilename The filename to parse.
533 */
534char *kldrHlpGetFilename(const char *pszFilename)
535{
536 const char *pszLast = NULL;
537 for (;;)
538 {
539 char ch = *pszFilename;
540#if defined(__OS2__) || defined(__WIN__)
541 if (ch == '/' || ch == '\\' || ch == ':')
542 {
543 while ((ch = *++pszFilename) == '/' || ch == '\\' || ch == ':')
544 /* nothing */;
545 pszLast = pszFilename;
546 }
547#else
548 if (ch == '/')
549 {
550 while ((ch = *++pszFilename) == '/')
551 /* betsuni */;
552 pszLast = pszFilename;
553 }
554#endif
555 if (!ch)
556 return (char *)(pszLast ? pszLast : pszFilename);
557 pszFilename++;
558 }
559}
560
561
562/**
563 * Gets the filename suffix.
564 *
565 * @returns Pointer to where the suffix starts within the string pointed to by pszFilename.
566 * @returns Pointer to the terminator char if no suffix.
567 * @param pszFilename The filename to parse.
568 */
569char *kldrHlpGetSuff(const char *pszFilename)
570{
571 const char *pszDot = NULL;
572 pszFilename = kldrHlpGetFilename(pszFilename);
573 for (;;)
574 {
575 char ch = *pszFilename;
576 if (ch == '.')
577 {
578 while ((ch = *++pszFilename) == '.')
579 /* nothing */;
580 if (ch)
581 pszDot = pszFilename - 1;
582 }
583 if (!ch)
584 return (char *)(pszDot ? pszDot : pszFilename);
585 pszFilename++;
586 }
587}
588
589
590/**
591 * Gets the filename extention.
592 *
593 * @returns Pointer to where the extension starts within the string pointed to by pszFilename.
594 * @returns Pointer to the terminator char if no extension.
595 * @param pszFilename The filename to parse.
596 */
597char *kldrHlpGetExt(const char *pszFilename)
598{
599 char *psz = kldrHlpGetSuff(pszFilename);
600 return *psz ? psz + 1 : psz;
601}
602
603
604
605/**
606 * Terminate the process.
607 *
608 * @param rc The exit status.
609 */
610void kldrHlpExit(int rc)
611{
612 for (;;)
613 {
614#ifdef __OS2__
615 DosExit(EXIT_PROCESS, rc);
616
617#elif defined(__WIN__)
618 TerminateProcess(GetCurrentProcess(), rc);
619
620#else
621# error "Port me"
622#endif
623 kldrHlpAssert(!"Impossible");
624 }
625}
626
627
628/**
629 * Sleep for a number of milliseconds.
630 * @param cMillies Number of milliseconds to sleep.
631 */
632void kldrHlpSleep(unsigned cMillies)
633{
634#ifdef __OS2__
635 DosSleep(cMillies);
636#elif defined(__WIN__)
637 Sleep(cMillies);
638#else
639 usleep(cMillies * 1000);
640#endif
641}
642
643
644/**
645 * Converts an signed integer to an ascii string.
646 *
647 * @returns psz.
648 * @param psz Pointer to the output buffer.
649 * @param cch The size of the output buffer.
650 * @param lVal The value.
651 * @param iBase The base to format it. (2,8,10 or 16)
652 */
653char *kldrHlpInt2Ascii(char *psz, size_t cch, long lVal, unsigned iBase)
654{
655 static const char s_szDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
656 char *pszRet = psz;
657
658 if (cch >= (lVal < 0 ? 3U : 2U) && psz)
659 {
660 /* prefix */
661 if (lVal < 0)
662 {
663 *psz++ = '-';
664 cch--;
665 lVal = -lVal;
666 }
667
668 /* the digits */
669 do
670 {
671 *psz++ = s_szDigits[lVal % iBase];
672 cch--;
673 lVal /= iBase;
674 } while (lVal && cch > 1);
675
676 /* overflow indicator */
677 if (lVal)
678 psz[-1] = '+';
679 }
680 else if (!pszRet)
681 return pszRet;
682 else if (cch < 1 || !pszRet)
683 return pszRet;
684 else
685 *psz++ = '+';
686 *psz = '\0';
687
688 return pszRet;
689}
690
691
692/**
693 * Writes a assert string with unix lineendings.
694 *
695 * @param pszMsg The string.
696 */
697static void kldrHlpAssertWrite(const char *pszMsg)
698{
699#if defined(__OS2__) || defined(__WIN__)
700 /*
701 * Line by line.
702 */
703 ULONG cbWritten;
704 const char *pszNl = kLdrHlpStrChr(pszMsg, '\n');
705 while (pszNl)
706 {
707 cbWritten = pszNl - pszMsg;
708
709#ifdef __OS2__
710 if (cbWritten)
711 DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten);
712 DosWrite((HFILE)2, "\r\n", 2, &cbWritten);
713#else /* __WIN32__ */
714 if (cbWritten)
715 WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL);
716 WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL);
717#endif
718
719 /* next */
720 pszMsg = pszNl + 1;
721 pszNl = kLdrHlpStrChr(pszMsg, '\n');
722 }
723
724 /*
725 * Remaining incomplete line.
726 */
727 if (*pszMsg)
728 {
729 cbWritten = kLdrHlpStrLen(pszMsg);
730#ifdef __OS2__
731 DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten);
732#else /* __WIN32__ */
733 WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL);
734#endif
735 }
736
737#else
738# error "port me"
739#endif
740}
741
742
743/**
744 * Internal worker for the kLdrHlpAssert() macro.
745 *
746 * @param pszExpr The assert expression.
747 * @param pszFile The filename.
748 * @param iLine The line number.
749 * @param pszFunction The function name.
750 */
751void kldrHlpAssertMsg(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction)
752{
753 char szLine[16];
754
755 kldrHlpAssertWrite("\n!!!kLdr Assertion Failed!!!\nExpression: ");
756 kldrHlpAssertWrite(pszExpr);
757 kldrHlpAssertWrite("\nAt: ");
758 kldrHlpAssertWrite(pszFile);
759 kldrHlpAssertWrite("(");
760 kldrHlpAssertWrite(kldrHlpInt2Ascii(szLine, sizeof(szLine), iLine, 10));
761 kldrHlpAssertWrite(") ");
762 kldrHlpAssertWrite(pszFunction);
763 kldrHlpAssertWrite("\n");
764}
765
766
767#ifdef kLdrHlpStrChr_needed
768char *kLdrHlpStrChr(const char *psz, int ch)
769{
770 while (*psz)
771 {
772 if (*psz == ch)
773 return (char *)psz;
774 psz++;
775 }
776 return NULL;
777}
778#endif
779
780
781#ifdef kLdrHlpStrChr_needed
782void *kLdrHlpMemChr(const void *pv, int ch, size_t cb)
783{
784 const uint8_t *pb = (const uint8_t *)pv;
785 const uint8_t b = (uint8_t)ch;
786 while (cb)
787 {
788 if (*pb == b)
789 return (void *)pb;
790 pb++;
791 }
792 return NULL;
793}
794#endif
795
796
797int kLdrHlpMemIComp(const void *pv1, const void *pv2, size_t cb)
798{
799 const uint8_t *pb1 = (const uint8_t *)pv1;
800 const uint8_t *pb2 = (const uint8_t *)pv2;
801 while (cb)
802 {
803 if (*pb1 != *pb2)
804 {
805 const uint8_t u1 = *pb1 >= 'a' && *pb1 <= 'z' ? *pb1 - 'a' : *pb1;
806 const uint8_t u2 = *pb2 >= 'a' && *pb2 <= 'z' ? *pb2 - 'a' : *pb2;
807 if (u1 != u2)
808 return (int)*pb1 - (int)*pb2;
809 }
810 pb1++;
811 pb2++;
812 }
813 return 0;
814}
815
816
817int kLdrHlpStrIComp(const char *pv1, const char *pv2)
818{
819 const uint8_t *pb1 = (const uint8_t *)pv1;
820 const uint8_t *pb2 = (const uint8_t *)pv2;
821 for (;;)
822 {
823 if (*pb1 != *pb2)
824 {
825 const uint8_t u1 = *pb1 >= 'a' && *pb1 <= 'z' ? *pb1 - 'a' : *pb1;
826 const uint8_t u2 = *pb2 >= 'a' && *pb2 <= 'z' ? *pb2 - 'a' : *pb2;
827 if (u1 != u2)
828 return (int)*pb1 - (int)*pb2;
829 }
830 if (!*pb1)
831 break;
832 pb1++;
833 pb2++;
834 }
835 return 0;
836}
837
Note: See TracBrowser for help on using the repository browser.