home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / utils.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  15KB  |  493 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: UTILS.C
  14. *
  15. * standard file-reading utilities.
  16. *
  17. * Functions:
  18. *
  19. * readfile_new()
  20. * readfile_next()
  21. * readfile_delete()
  22. * utils_CompPath()
  23. * has_string()
  24. * utils_isblank()
  25. * StringInput()
  26. * dodlg_stringin()
  27. *
  28. * Comments:
  29. *
  30. ****************************************************************************/
  31.  
  32. #include <windows.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include "gutils.h"
  37. #include "gutilsrc.h"
  38.  
  39.  
  40. /*
  41.  * we need an instance handle. this should be the dll instance
  42.  */
  43. extern HANDLE hLibInst;
  44.  
  45.  
  46.  
  47. /*
  48.  * -- forward declaration of procedures -----------------------------------
  49.  */
  50. int FAR PASCAL dodlg_stringin(HWND hDlg, UINT message, UINT wParam, LONG lParam);
  51.  
  52.  
  53.  
  54.  
  55. /*-- readfile: buffered line input ------------------------------*/
  56.  
  57. /*
  58.  * set of functions to read a line at a time from a file, using
  59.  * a buffer to read a block at a time from the file
  60.  *
  61.  */
  62.  
  63. /*
  64.  * a FILEBUFFER handle is a pointer to a struct filebuffer
  65.  */
  66. struct filebuffer {
  67.         int fh;         /* open file handle */
  68.         PSTR start;     /* offset within buffer of next character */
  69.         PSTR last;      /* offset within buffer of last valid char read in */
  70.  
  71.         char buffer[512];
  72. };
  73.  
  74. /***************************************************************************
  75.  * Function: readfile_new
  76.  *
  77.  * Purpose:
  78.  *
  79.  * Initialise a filebuffer and return a handle to it
  80.  */
  81. FILEBUFFER APIENTRY
  82. readfile_new(int fh)
  83. {
  84.         FILEBUFFER fbuf;
  85.  
  86.         fbuf = (FILEBUFFER) LocalLock(LocalAlloc(LHND, sizeof(struct filebuffer)));
  87.         if (fbuf == NULL) {
  88.                 return(NULL);
  89.         }
  90.  
  91.         fbuf->fh = fh;
  92.         fbuf->start = fbuf->buffer;
  93.         fbuf->last = fbuf->buffer;
  94.         /* return file pointer to beginning of file */
  95.         _llseek(fh, 0, 0);
  96.  
  97.         return(fbuf);
  98. }
  99.  
  100. /***************************************************************************
  101.  * Function: readfile_next
  102.  *
  103.  * Purpose:
  104.  *
  105.  * Get the next line from a file. Returns a pointer to the line
  106.  * in the buffer - so copy it before changing it.
  107.  *
  108.  * The line is *not* null-terminated. *plen is set to the length of the
  109.  * line.
  110.  */
  111. LPSTR APIENTRY
  112. readfile_next(FILEBUFFER fbuf, int FAR * plen)
  113. {
  114.         PSTR cstart;
  115.  
  116.         /* look for an end of line in the buffer we have*/
  117.         for (cstart = fbuf->start; cstart < fbuf->last; cstart++) {
  118.  
  119.                 if (*cstart == '\n') {
  120.                         *plen = (cstart - fbuf->start) + 1;
  121.                         cstart = fbuf->start;
  122.                         fbuf->start += *plen;
  123.                         return(cstart);
  124.                 }
  125.  
  126.         }
  127.  
  128.         /* no cr in this buffer - this buffer contains a partial line.
  129.          * copy the partial up to the beginning of the buffer, and
  130.          * adjust the pointers to reflect this move
  131.          */
  132.         Old_strncpy(fbuf->buffer, fbuf->start, fbuf->last - fbuf->start);
  133.         fbuf->last = &fbuf->buffer[fbuf->last - fbuf->start];
  134.         fbuf->start = fbuf->buffer;
  135.  
  136.         /* read in to fill the block */
  137.         fbuf->last += _lread(fbuf->fh, fbuf->last,
  138.                         &fbuf->buffer[sizeof(fbuf->buffer)] - fbuf->last);
  139.  
  140.         /* look for an end of line in the newly filled buffer */
  141.         for (cstart = fbuf->start; cstart < fbuf->last; cstart++) {
  142.  
  143.                 if (*cstart == '\n') {
  144.                         *plen = (cstart - fbuf->start) + 1;
  145.                         cstart = fbuf->start;
  146.                         fbuf->start += *plen;
  147.                         return(cstart);
  148.                 }
  149.         }
  150.  
  151.  
  152.         /* still no end of line. either the buffer is empty -
  153.          * because of end of file - or the line is longer than
  154.          * the buffer. in either case, return all that we have
  155.          */
  156.         *plen = fbuf->last - fbuf->start;
  157.         { // for JAPAN (nChars != nBytes)
  158.             PSTR ptr;
  159.             for(ptr=fbuf->start;ptr<fbuf->last;ptr++) ;
  160.             if(ptr!=fbuf->last && *plen) {
  161.                 --(*plen);
  162.                 --(fbuf->last);
  163.                 _llseek(fbuf->fh,-1,1);
  164.             }
  165.         }
  166.         cstart = fbuf->start;
  167.         fbuf->start += *plen;
  168.         if (*plen == 0) {
  169.                 return(NULL);
  170.         } else {
  171.                 return(cstart);
  172.         }
  173. }
  174.  
  175.  
  176. /***************************************************************************
  177.  * Function: readfile_delete
  178.  *
  179.  * Purpose:
  180.  *
  181.  * Delete a FILEBUFFER - close the file handle and free the buffer
  182.  */
  183. void APIENTRY
  184. readfile_delete(FILEBUFFER fbuf)
  185. {
  186.         _lclose(fbuf->fh);
  187.  
  188.         LocalUnlock(LocalHandle( (PSTR) fbuf));
  189.         LocalFree(LocalHandle( (PSTR) fbuf));
  190. }
  191.  
  192.  
  193. /* ----------- things for strings-------------------------------------*/
  194.  
  195.  
  196. /*
  197.  * Compare two pathnames, and if not equal, decide which should come first.
  198.  * Both path names should be lower cased by AnsiLowerBuff before calling.
  199.  *
  200.  * Returns 0 if the same, -1 if left is first, and +1 if right is first.
  201.  *
  202.  * The comparison is such that all filenames in a directory come before any
  203.  * file in a subdirectory of that directory.
  204.  *
  205.  * Given direct\thisfile v. direct\subdir\thatfile, we take
  206.  * thisfile < thatfile   even though it is second alphabetically.
  207.  * We do this by picking out the shorter path
  208.  * (fewer path elements), and comparing them up till the last element of that
  209.  * path (in the example: compare the 'dir\' in both cases.)
  210.  * If they are the same, then the name with more path elements is
  211.  * in a subdirectory, and should come second.
  212.  *
  213.  * We have had trouble with apparently multiple collating sequences and
  214.  * the position of \ in the sequence.  To eliminate this trouble
  215.  * a. EVERYTHING is mapped to lower case first (actually this is done
  216.  *    before calling this routine).
  217.  * b. All comparison is done by using lstrcmpi with two special cases.
  218.  *    1. Subdirs come after parents as noted above
  219.  *    2. \ must compare low so that fred2\x > fred\x in the same way
  220.  *       that fred2 < fred.  Unfortunately in ANSI '2' < '\\'
  221.  *
  222.  */
  223. int APIENTRY
  224. utils_CompPath(LPSTR left, LPSTR right)
  225. {
  226.         int compval;            // provisional value of comparison
  227.  
  228.         if (left==NULL) return -1;        // empty is less than anything else
  229.         else if (right==NULL) return 1;  // anything is greater than empty
  230.  
  231.         for (; ; ) {
  232.                 if (*left=='\0' && *right=='\0') return 0;
  233.                 if (*left=='\0')  return -1;
  234.                 if (*right=='\0')  return 1;
  235.                 if (IsDBCSLeadByte(*left) || IsDBCSLeadByte(*right)) {
  236.                         if (*right != *left) {
  237.                                 compval = (*left - *right);
  238.                                 break;
  239.                         }
  240.                         ++left;
  241.                         ++right;
  242.                         if (*right != *left) {
  243.                                 compval = (*left - *right);
  244.                                 break;
  245.                         }
  246.                         ++left;
  247.                         ++right;
  248.                 } else {
  249.                 if (*right==*left)  {++left; ++right; continue;}
  250.                 if (*left=='\\') {compval = -1; break;}
  251.                 if (*right=='\\') {compval = 1; break;}
  252.                 compval = (*left - *right);
  253.                 break;
  254.                 }
  255.         }
  256.  
  257.         /* We have detected a difference.  If the rest of one
  258.            of the strings (including the current character) contains
  259.            some \ characters, but the other one does not, then all
  260.            elements up to the last element of the one with the fewer
  261.            elements are equal and so the other one lies in a subdir
  262.            and so compares greater i.e. x\y\f > x\f
  263.            Otherwise compval tells the truth.
  264.         */
  265.  
  266.         left = strchr(left, '\\');
  267.         right = strchr(right, '\\');
  268.         if (left && !right) return 1;
  269.         if (right && !left) return -1;
  270.  
  271.         return compval;
  272.  
  273. } /* utils_CompPath */
  274.  
  275.  
  276. /***************************************************************************
  277.  * Function: hash_string
  278.  *
  279.  * Purpose:
  280.  *
  281.  * Generate a hashcode for a null-terminated ascii string.
  282.  *
  283.  * If bIgnoreBlanks is set, then ignore all spaces and tabs in calculating
  284.  * the hashcode.
  285.  *
  286.  * Multiply each character by a function of its position and sum these.
  287.  * The function chosen is to multiply the position by successive
  288.  * powers of a large number.
  289.  * The large multiple ensures that anagrams generate different hash
  290.  * codes.
  291.  */
  292. DWORD APIENTRY
  293. hash_string(LPSTR string, BOOL bIgnoreBlanks)
  294. {
  295. #define LARGENUMBER     6293815
  296.  
  297.         DWORD sum = 0;
  298.         DWORD multiple = LARGENUMBER;
  299.         int index = 1;
  300.  
  301.         while (*string != '\0') {
  302.  
  303.                 if (bIgnoreBlanks) {
  304.                         while ( (*string == ' ') || (*string == '\t')) {
  305.                                 string = CharNext(string);
  306.                         }
  307.                 }
  308.  
  309.                 sum += multiple * index++ * (*string++);
  310.                 multiple *= LARGENUMBER;
  311.         }
  312.         return(sum);
  313. }
  314.  
  315.  
  316. /***************************************************************************
  317.  * Function: utils_isblank
  318.  *
  319.  * Purpose:
  320.  *
  321.  * Return TRUE iff the string is blank.  Blank means the same as
  322.  * the characters which are ignored in hash_string when ignore_blanks is set
  323.  */
  324. BOOL APIENTRY
  325. utils_isblank(LPSTR string)
  326. {
  327.         while ( (*string == ' ') || (*string == '\t')) {
  328.                 string = CharNext(string);
  329.         }
  330.  
  331.         /* having skipped all the blanks, do we see the end delimiter? */
  332.         return (*string == '\0' || *string == '\r' || *string == '\n');
  333. }
  334.  
  335.  
  336.  
  337. /* --- simple string input -------------------------------------- */
  338.  
  339. /*
  340.  * static variables for communication between function and dialog
  341.  */
  342. LPSTR dlg_result;
  343. int dlg_size;
  344. LPSTR dlg_prompt, dlg_default, dlg_caption;
  345.  
  346. /***************************************************************************
  347.  * Function: StringInput
  348.  *
  349.  * Purpose:
  350.  *
  351.  * Input of a single text string, using a simple dialog.
  352.  *
  353.  * Returns TRUE if ok, or FALSE if error or user canceled. If TRUE,
  354.  * puts the string entered into result (up to resultsize characters).
  355.  *
  356.  * Prompt is used as the prompt string, caption as the dialog caption and
  357.  * default as the default input. All of these can be null.
  358.  */
  359.  
  360. int APIENTRY
  361. StringInput(LPSTR result, int resultsize, LPSTR prompt, LPSTR caption,
  362.                 LPSTR def_input)
  363. {
  364.         DLGPROC lpProc;
  365.         BOOL fOK;
  366.  
  367.         /* copy args to static variable so that winproc can see them */
  368.  
  369.         dlg_result = result;
  370.         dlg_size = resultsize;
  371.         dlg_prompt = prompt;
  372.         dlg_caption = caption;
  373.         dlg_default = def_input;
  374.  
  375.         lpProc = (DLGPROC)MakeProcInstance((WNDPROC)dodlg_stringin, hLibInst);
  376.         fOK = DialogBox(hLibInst, "StringInput", GetFocus(), lpProc);
  377.         FreeProcInstance((WNDPROC)lpProc);
  378.  
  379.         return(fOK);
  380. }
  381.  
  382. /***************************************************************************
  383.  * Function: dodlg_stringin
  384.  *
  385.  */
  386. int FAR PASCAL
  387. dodlg_stringin(HWND hDlg, UINT message, UINT wParam, LONG lParam)
  388. {
  389.         switch(message) {
  390.  
  391.         case WM_INITDIALOG:
  392.                 if (dlg_caption != NULL) {
  393.                         SendMessage(hDlg, WM_SETTEXT, 0, (LONG) dlg_caption);
  394.                 }
  395.                 if (dlg_prompt != NULL) {
  396.                         SetDlgItemText(hDlg, IDD_LABEL, dlg_prompt);
  397.                 }
  398.                 if (dlg_default) {
  399.                         SetDlgItemText(hDlg, IDD_FILE, dlg_default);
  400.                 }
  401.                 return(TRUE);
  402.  
  403.         case WM_COMMAND:
  404.                 switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  405.  
  406.                 case IDCANCEL:
  407.                         EndDialog(hDlg, FALSE);
  408.                         return(TRUE);
  409.  
  410.                 case IDOK:
  411.                         GetDlgItemText(hDlg, IDD_FILE, dlg_result, dlg_size);
  412.                         EndDialog(hDlg, TRUE);
  413.                         return(TRUE);
  414.                 }
  415.         }
  416.         return (FALSE);
  417. }
  418.  
  419. /***************************************************************************
  420.  * Function: My_mbschr
  421.  *
  422.  * Purpose:
  423.  *
  424.  * DBCS version of strchr
  425.  *
  426.  */
  427. unsigned char * _CRTAPI1 My_mbschr(
  428.     unsigned char *psz, unsigned short uiSep)
  429. {
  430.     while (*psz != '\0' && *psz != uiSep) {
  431.         psz = CharNext(psz);
  432.     }
  433.     return *psz == uiSep ? psz : NULL;
  434. }
  435. /***************************************************************************
  436.  * Function: My_mbsncpy
  437.  *
  438.  * Purpose:
  439.  *
  440.  * DBCS version of strncpy
  441.  *
  442.  */
  443. unsigned char * _CRTAPI1 My_mbsncpy(
  444.     unsigned char *psz1, const unsigned char *psz2, size_t Length)
  445. {
  446.         int nLen = (int)Length;
  447.     unsigned char *pszSv = psz1;
  448.  
  449.     while (0 < nLen) {
  450.         if (*psz2 == '\0') {
  451.             *psz1++ = '\0';
  452.             nLen--;
  453.         } else if (IsDBCSLeadByte(*psz2)) {
  454.             if (nLen == 1) {
  455.                 *psz1 = '\0';
  456.             } else {
  457.                 *psz1++ = *psz2++;
  458.                 *psz1++ = *psz2++;
  459.             }
  460.             nLen -= 2;
  461.         } else {
  462.             *psz1++ = *psz2++;
  463.             nLen--;
  464.         }
  465.     }
  466.     return pszSv;
  467. }
  468.  
  469. /***************************************************************************
  470.  * Function: LoadRcString
  471.  *
  472.  * Purpose: Loads a resource string from string table and returns a pointer
  473.  *          to the string.
  474.  *
  475.  * Parameters: wID - resource string id
  476.  *
  477.  */
  478. LPTSTR APIENTRY LoadRcString(UINT wID)
  479. {
  480.     static TCHAR szBuf[512];
  481.  
  482.     LoadString((HANDLE)GetModuleHandle(NULL),wID,szBuf,sizeof(szBuf));
  483.     return szBuf;
  484. }
  485.  
  486. LPTSTR APIENTRY LoadRcString2(UINT wID)
  487. {
  488.     static TCHAR szBuf[512];
  489.  
  490.     LoadString((HANDLE)GetModuleHandle(NULL),wID,szBuf,sizeof(szBuf));
  491.     return szBuf;
  492. }
  493.