|
|
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.