|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 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: 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: cstart = fbuf->start; ! 158: fbuf->start += *plen; ! 159: if (*plen == 0) { ! 160: return(NULL); ! 161: } else { ! 162: return(cstart); ! 163: } ! 164: } ! 165: ! 166: ! 167: /*************************************************************************** ! 168: * Function: readfile_delete ! 169: * ! 170: * Purpose: ! 171: * ! 172: * Delete a FILEBUFFER - close the file handle and free the buffer ! 173: */ ! 174: void APIENTRY ! 175: readfile_delete(FILEBUFFER fbuf) ! 176: { ! 177: _lclose(fbuf->fh); ! 178: ! 179: LocalUnlock(LocalHandle( (PSTR) fbuf)); ! 180: LocalFree(LocalHandle( (PSTR) fbuf)); ! 181: } ! 182: ! 183: ! 184: /* ----------- things for strings-------------------------------------*/ ! 185: ! 186: ! 187: /* ! 188: * Compare two pathnames, and if not equal, decide which should come first. ! 189: * Both path names should be lower cased by AnsiLowerBuff before calling. ! 190: * ! 191: * Returns 0 if the same, -1 if left is first, and +1 if right is first. ! 192: * ! 193: * The comparison is such that all filenames in a directory come before any ! 194: * file in a subdirectory of that directory. ! 195: * ! 196: * Given direct\thisfile v. direct\subdir\thatfile, we take ! 197: * thisfile < thatfile even though it is second alphabetically. ! 198: * We do this by picking out the shorter path ! 199: * (fewer path elements), and comparing them up till the last element of that ! 200: * path (in the example: compare the 'dir\' in both cases.) ! 201: * If they are the same, then the name with more path elements is ! 202: * in a subdirectory, and should come second. ! 203: * ! 204: * We have had trouble with apparently multiple collating sequences and ! 205: * the position of \ in the sequence. To eliminate this trouble ! 206: * a. EVERYTHING is mapped to lower case first (actually this is done ! 207: * before calling this routine). ! 208: * b. All comparison is done by using lstrcmpi with two special cases. ! 209: * 1. Subdirs come after parents as noted above ! 210: * 2. \ must compare low so that fred2\x > fred\x in the same way ! 211: * that fred2 < fred. Unfortunately in ANSI '2' < '\\' ! 212: * ! 213: */ ! 214: int APIENTRY ! 215: utils_CompPath(LPSTR left, LPSTR right) ! 216: { ! 217: int compval; // provisional value of comparison ! 218: ! 219: if (left==NULL) return -1; // empty is less than anything else ! 220: else if (right==NULL) return 1; // anything is greater than empty ! 221: ! 222: for (; ; ) { ! 223: if (*left=='\0' && *right=='\0') return 0; ! 224: if (*left=='\0') return -1; ! 225: if (*right=='\0') return 1; ! 226: if (*right==*left) {++left; ++right; continue;} ! 227: if (*left=='\\') {compval = -1; break;} ! 228: if (*right=='\\') {compval = 1; break;} ! 229: compval = (*left - *right); ! 230: break; ! 231: } ! 232: ! 233: /* We have detected a difference. If the rest of one ! 234: of the strings (including the current character) contains ! 235: some \ characters, but the other one does not, then all ! 236: elements up to the last element of the one with the fewer ! 237: elements are equal and so the other one lies in a subdir ! 238: and so compares greater i.e. x\y\f > x\f ! 239: Otherwise compval tells the truth. ! 240: */ ! 241: ! 242: left = strchr(left, '\\'); ! 243: right = strchr(right, '\\'); ! 244: if (left && !right) return 1; ! 245: if (right && !left) return -1; ! 246: ! 247: return compval; ! 248: ! 249: } /* utils_CompPath */ ! 250: ! 251: ! 252: /*************************************************************************** ! 253: * Function: hash_string ! 254: * ! 255: * Purpose: ! 256: * ! 257: * Generate a hashcode for a null-terminated ascii string. ! 258: * ! 259: * If bIgnoreBlanks is set, then ignore all spaces and tabs in calculating ! 260: * the hashcode. ! 261: * ! 262: * Multiply each character by a function of its position and sum these. ! 263: * The function chosen is to multiply the position by successive ! 264: * powers of a large number. ! 265: * The large multiple ensures that anagrams generate different hash ! 266: * codes. ! 267: */ ! 268: DWORD APIENTRY ! 269: hash_string(LPSTR string, BOOL bIgnoreBlanks) ! 270: { ! 271: #define LARGENUMBER 6293815 ! 272: ! 273: DWORD sum = 0; ! 274: DWORD multiple = LARGENUMBER; ! 275: int index = 1; ! 276: ! 277: while (*string != '\0') { ! 278: ! 279: if (bIgnoreBlanks) { ! 280: while ( (*string == ' ') || (*string == '\t')) { ! 281: string++; ! 282: } ! 283: } ! 284: ! 285: sum += multiple * index++ * (*string++); ! 286: multiple *= LARGENUMBER; ! 287: } ! 288: return(sum); ! 289: } ! 290: ! 291: ! 292: /*************************************************************************** ! 293: * Function: utils_isblank ! 294: * ! 295: * Purpose: ! 296: * ! 297: * Return TRUE iff the string is blank. Blank means the same as ! 298: * the characters which are ignored in hash_string when ignore_blanks is set ! 299: */ ! 300: BOOL APIENTRY ! 301: utils_isblank(LPSTR string) ! 302: { ! 303: while ( (*string == ' ') || (*string == '\t')) { ! 304: string++; ! 305: } ! 306: ! 307: /* having skipped all the blanks, do we see the end delimiter? */ ! 308: return (*string == '\0' || *string == '\r' || *string == '\n'); ! 309: } ! 310: ! 311: ! 312: ! 313: /* --- simple string input -------------------------------------- */ ! 314: ! 315: /* ! 316: * static variables for communication between function and dialog ! 317: */ ! 318: LPSTR dlg_result; ! 319: int dlg_size; ! 320: LPSTR dlg_prompt, dlg_default, dlg_caption; ! 321: ! 322: /*************************************************************************** ! 323: * Function: StringInput ! 324: * ! 325: * Purpose: ! 326: * ! 327: * Input of a single text string, using a simple dialog. ! 328: * ! 329: * Returns TRUE if ok, or FALSE if error or user canceled. If TRUE, ! 330: * puts the string entered into result (up to resultsize characters). ! 331: * ! 332: * Prompt is used as the prompt string, caption as the dialog caption and ! 333: * default as the default input. All of these can be null. ! 334: */ ! 335: ! 336: int APIENTRY ! 337: StringInput(LPSTR result, int resultsize, LPSTR prompt, LPSTR caption, ! 338: LPSTR def_input) ! 339: { ! 340: DLGPROC lpProc; ! 341: BOOL fOK; ! 342: ! 343: /* copy args to static variable so that winproc can see them */ ! 344: ! 345: dlg_result = result; ! 346: dlg_size = resultsize; ! 347: dlg_prompt = prompt; ! 348: dlg_caption = caption; ! 349: dlg_default = def_input; ! 350: ! 351: lpProc = (DLGPROC)MakeProcInstance((WNDPROC)dodlg_stringin, hLibInst); ! 352: fOK = DialogBox(hLibInst, "StringInput", GetFocus(), lpProc); ! 353: FreeProcInstance((WNDPROC)lpProc); ! 354: ! 355: return(fOK); ! 356: } ! 357: ! 358: /*************************************************************************** ! 359: * Function: dodlg_stringin ! 360: * ! 361: */ ! 362: int FAR PASCAL ! 363: dodlg_stringin(HWND hDlg, UINT message, UINT wParam, LONG lParam) ! 364: { ! 365: switch(message) { ! 366: ! 367: case WM_INITDIALOG: ! 368: if (dlg_caption != NULL) { ! 369: SendMessage(hDlg, WM_SETTEXT, 0, (LONG) dlg_caption); ! 370: } ! 371: if (dlg_prompt != NULL) { ! 372: SetDlgItemText(hDlg, IDD_LABEL, dlg_prompt); ! 373: } ! 374: if (dlg_default) { ! 375: SetDlgItemText(hDlg, IDD_FILE, dlg_default); ! 376: } ! 377: return(TRUE); ! 378: ! 379: case WM_COMMAND: ! 380: switch(GET_WM_COMMAND_ID(wParam, lParam)) { ! 381: ! 382: case IDCANCEL: ! 383: EndDialog(hDlg, FALSE); ! 384: return(TRUE); ! 385: ! 386: case IDOK: ! 387: GetDlgItemText(hDlg, IDD_FILE, dlg_result, dlg_size); ! 388: EndDialog(hDlg, TRUE); ! 389: return(TRUE); ! 390: } ! 391: } ! 392: return (FALSE); ! 393: } ! 394:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.