source: sans/XOP_Dev/EventLoader/EventLoadWave.cpp @ 996

Last change on this file since 996 was 996, checked in by srkline, 7 years ago

changes to the project and files for Toolkit 7, Xcode 7, and 64-bit version of Event Loader XOP

Successful on Mac, untested on Ein (don't have a machine or compiler yet)

File size: 28.9 KB
Line 
1/*      EventLoadWave.cpp
2       
3        This XOP is an example for XOP programmers who want to write
4        file loader XOPs. Thus, we have kept is as simple as possible.
5       
6        The file is assumed to be tab- or comma-delimited. It is assumed to contain
7        numeric data, optionally preceded by a row of column names. If column names
8        are present, they are assumed to be on the first line, with the numeric data
9        starting on the second line. If there are no column names, then the numeric
10        data is assumed to start on the first line.
11       
12        See "SimpleLoadWave Help" for an explanation of how to use the SimpleLoadWave XOP.
13       
14        HR, 10/19/96:
15                Changed to make CR, CRLF or LF be acceptable end-of-line markers.
16               
17                It does not handle LFCR which is a deviant form created by some
18                whacko file translators.
19       
20        HR, 980427:
21                Made platform-independent.
22               
23        HR, 020919:
24                Revamped to use Operation Handler so that the SimpleLoadWave operation
25                can be called from a user function.
26       
27        HR, 091021
28                Updated for 64-bit compatibility.
29*/
30
31#include "XOPStandardHeaders.h"                 // Include ANSI headers, Mac headers, IgorXOP.h, XOP.h and XOPSupport.h
32#include "EventLoadWave.h"
33
34
35// from Teabag
36union AIMEvent {
37        unsigned int raw;
38        struct word {
39                unsigned short tildax : 8;
40                unsigned short y : 8;
41                unsigned short time : 13;
42                unsigned short ppto : 1;
43                unsigned short type : 2;
44        } word;
45} AimEvent;
46
47
48// counters for the events
49struct counter {
50        int XYevents;
51        int num0;
52        int num1;
53        int num2;
54        int num3;
55        int zeros;
56        int t0;
57        int minor_rollover;
58        int major_rollover;
59        int pp;
60        int dl;
61} counter;
62
63
64////////
65
66
67// Global Variables
68static char gSeparatorsStr[] = {'\t', ',', 0x00};       // Tab or comma separates one column from the next.
69
70
71/*      TellFileType(fileMessage, fullFilePath, fileLoaderFlags)
72
73        Shows type of file being loaded in history.
74*/
75static void
76TellFileType(const char* fileMessage, const char* fullFilePath, int fileLoaderFlags)
77{
78        char temp[MAX_PATH_LEN + 100 + 1];
79       
80        if ((fileLoaderFlags & FILE_LOADER_QUIET) == 0) {
81                sprintf(temp, "%s \"%s\""CR_STR, fileMessage, fullFilePath);
82                XOPNotice(temp);
83        }
84}
85
86/*      FinishWave(ciPtr, fileLoaderFlags)
87
88        Finalizes waves after load.
89       
90        ciPtr points to the column info for this column.
91       
92        It returns 0 or an error code.
93*/
94static int
95FinishWave(ColumnInfoPtr ciPtr, int fileLoaderFlags)
96{
97        waveHndl waveHandle;
98        char temp[256];
99        CountInt numPoints;
100       
101        waveHandle = ciPtr->waveHandle;
102        WaveHandleModified(waveHandle);
103        numPoints = WavePoints(waveHandle);
104
105        if ((fileLoaderFlags & FILE_LOADER_QUIET) == 0) {                       // Want message?
106                sprintf(temp, "%s loaded, %lld points"CR_STR, ciPtr->waveName, (SInt64)numPoints);
107                XOPNotice(temp);
108        }
109       
110        return 0;
111}
112
113/*      FindNumberOfRows(fileRef, buffer, bufferLength, rowsInFilePtr)
114
115        Returns via rowsInFilePtr the number of rows in the file, starting
116        from the current file position. Restores the file position when done.
117       
118        A row is considered to consist of 0 or more characters followed by a
119        CR or LF or CRLF except that the last row does not need to have any of
120        these.
121       
122        Returns 0 or error code.
123*/
124static int
125FindNumberOfRows(XOP_FILE_REF fileRef, char* buffer, int bufferLength, CountInt* rowsInFilePtr)
126{
127        SInt64 origFPos;
128        int err;
129//      UInt32* numBytesReadPtr; // Output: number of bytes read
130       
131        *rowsInFilePtr = 0;
132
133        if (err = XOPGetFilePosition2(fileRef, &origFPos))
134                return err;
135       
136        while (1) {
137                if (err = XOPReadLine(fileRef, buffer, bufferLength, NULL)) {
138//              if (err = XOPReadLine(fileRef, buffer, bufferLength, numBytesReadPtr)) {
139                        if (XOPAtEndOfFile(fileRef))
140                                err = 0;
141                        break;
142                }
143//              if(numBytesReadPtr != NULL){
144                        *rowsInFilePtr += 1;
145//              }
146        }
147       
148        XOPSetFilePosition2(fileRef, origFPos);                 // Restore original file position.
149        return err;
150}
151
152/*      FindNumberOfColumns(fileRef, buffer, bufferLength, numColumnsPtr)
153
154        Returns via numColumnsPtr the number of columns in the file, starting
155        from the current file position. Restores the file position when done.
156       
157        A column is considered to consist of 0 or more characters followed by a
158        tab, comma, CR, LF or CRLF.
159       
160        Returns 0 or error code.
161*/
162static int
163FindNumberOfColumns(XOP_FILE_REF fileRef, char* buffer, int bufferLength, int* numColumnsPtr)
164{
165        SInt64 origFPos;
166        char* bufPtr;
167        char ch;
168        int err;
169       
170        *numColumnsPtr = 1;
171       
172        if (err = XOPGetFilePosition2(fileRef, &origFPos))
173                return err;
174
175        if (err = XOPReadLine(fileRef, buffer, bufferLength, NULL))
176                return err;
177       
178        bufPtr = buffer;
179        while(1) {
180                ch = *bufPtr++;
181                if (ch == 0)
182                        break;
183                if (strchr(gSeparatorsStr, ch))                         // Tab or comma separates one column from the next.
184                        *numColumnsPtr += 1;
185        }
186
187        XOPSetFilePosition2(fileRef, origFPos);                 // Restore original file position.
188       
189        return 0;
190}
191
192/*      ReadASCIINumber(bufPtrPtr, doublePtr)
193
194        Reads an ASCII number from the buffer.
195       
196        bufPtrPtr is a pointer to a variable that points to the next character
197        to be read in the current line. The line is null-terminated but does
198        not contain CR or LF.
199       
200        ReadASCIINumber returns the value via the pointer doublePtr.
201        It also advances *bufPtrPtr past the number just read.
202       
203        It returns the 0 if everything was OK or a non-zero error code.
204*/
205static int
206ReadASCIINumber(char** bufPtrPtr, double *doublePtr)
207{
208        char *bufPtr;
209        double d;
210        int hitColumnEnd;
211        int ch;
212       
213        bufPtr = *bufPtrPtr;                                    // Points to next character to read.
214       
215        // See if we have the end of the column before number.
216        hitColumnEnd = 0;
217        while (1) {
218                ch = *bufPtr;
219                if (ch == ' ') {                                        // Skip leading spaces.
220                        bufPtr += 1;
221                        continue;
222                }
223                if (ch==0 || strchr(gSeparatorsStr, ch))
224                        hitColumnEnd = 1;
225                break;                                                          // We've found the first non-space character.
226        }
227
228        if (hitColumnEnd || sscanf(bufPtr, " %lf", &d) <= 0)
229                *doublePtr = DOUBLE_NAN;
230        else
231                *doublePtr = d;
232
233        // Now figure out how many characters were really needed for number.
234        while (1) {                                                             // Search for tab or comma or null-terminator.
235                ch = *bufPtr;
236                if (ch == 0)
237                        break;
238                bufPtr += 1;
239                if (strchr(gSeparatorsStr, ch))
240                        break;
241        }
242       
243        *bufPtrPtr = bufPtr;                                    // Points to next character to be read.
244        return 0;               
245}
246
247/// simply scans through the whole file and counts the events as specified
248int ScanEvents(unsigned int lword) 
249{       
250        AimEvent.raw = lword;
251       
252        if(lword == 0) counter.zeros++;
253       
254        switch (AimEvent.word.type) {
255                case AIMTYPE_XY:                // 0
256                        if (AimEvent.word.ppto) counter.pp++;
257                        counter.num0++;
258                        counter.XYevents++;
259                        break;
260                case AIMTYPE_XYM:       // 2
261                        if (AimEvent.word.ppto) counter.pp++;
262                        counter.num2++;
263                        counter.XYevents++;
264                        break;
265                case AIMTYPE_MIR:       //1
266                        if (AimEvent.word.ppto) counter.t0++;
267                        counter.num1++;
268                        break;
269                case AIMTYPE_MAR:
270                        if (AimEvent.word.ppto) counter.t0++;
271                        counter.num3++;
272        }
273        return 1;
274}
275
276
277/*      LoadEventData(fileRef, buffer, bufferLength, fileLoaderFlags, caPtr, numRows, numColumns)
278
279        Loads simple tab or comma delimited data into waves.
280        caPtr points to locked array of column info (see EventLoadWave.h).
281        numColumns is number of columns in file.
282       
283        File mark is assumed pointing to start of first row of data.
284*/
285static int
286LoadEventData(
287        XOP_FILE_REF fileRef,
288        char* buffer, int bufferLength,
289        int fileLoaderFlags, ColumnInfoPtr caPtr,
290        CountInt numRows, CountInt numColumns)
291{
292//      ColumnInfoPtr ciPtr;
293        ColumnInfoPtr xLocPtr;
294        ColumnInfoPtr yLocPtr;
295        ColumnInfoPtr timePtr;
296//      int column;
297        IndexInt row;                   //IndexInt = long
298//      double doubleValue;
299        int isDouble,removeBadEvents;
300//      char* bufPtr;                           // Points to the next character in the current line of text.
301        int err;
302        //
303        char buf[128];          //TB
304        unsigned int lword;
305        long time_msw, time_lsw, x, y;
306        long nRoll, rolloverHappened;
307        double rollTime;                // declaring this as double forces a correct type conversion when calculating the time
308        double t,t_longest;             // these need to be double to hold the longest time values, unsigned long is not large enough
309        int numBad;
310        int numRemoved;
311        char bufStr[256];
312       
313        isDouble = fileLoaderFlags & FILE_LOADER_DOUBLE_PRECISION;
314        removeBadEvents = fileLoaderFlags & EVENT_REMOVE_BAD_EVENTS;            // this is == 256 if the flag is set
315        // -- so ((1) && 256) returns 1!
316
317//      sprintf(bufStr,"XOP removeBadEvents flag = %d\r",removeBadEvents);
318//      XOPNotice(bufStr);
319       
320        err = 0;
321
322        numBad = 0;
323        numRemoved = 0;
324        nRoll = 0;
325        rolloverHappened = 0;
326        rollTime = 67108864;            // == 2^26, units of 0.1 microseconds
327       
328
329        xLocPtr = caPtr + 0;
330        yLocPtr = caPtr + 1;
331        timePtr = caPtr + 2;   
332       
333        time_msw=0;
334        time_lsw=0;
335        t_longest = 0;
336        row = 0;
337       
338        if(removeBadEvents) {
339                // remove events at the beginning up to a type==2 so that the msw and lsw times are reset properly
340                while(fgets(buf,sizeof(buf),fileRef)) {
341                        if (sscanf(buf,"%x",&lword)) {
342                                AimEvent.raw = lword;
343                                if(AimEvent.word.type == 2) {
344                                        // this is the first event with a proper time value, so process the XY-time event as ususal
345                                        // and then break to drop to the main loop, where the next event == type 1
346                                        x = ~AimEvent.word.tildax & 127;
347                                        y = AimEvent.word.y & 127;
348                                        time_lsw = AimEvent.word.time;
349                                       
350                                        // this is the first point, be sure that row = 0
351                                        row = 0;
352                                        ((float*)xLocPtr->waveData)[row] = (float)x;
353                                        ((float*)yLocPtr->waveData)[row] = (float)y;
354                                        break;          //get out, and read the rest of the file as normal
355                                } else {
356                                        numBad++;
357                                        numRemoved++;
358                                }
359
360                        }
361                }
362        }
363       
364        sprintf(bufStr,"XOP numRemoved at beginning = %d\r",numRemoved);
365        XOPNotice(bufStr);
366       
367// now read in the main portion of the file... 
368        while(fgets(buf,sizeof(buf),fileRef)) {
369                if (sscanf(buf,"%x",&lword)) {
370                       
371                        AimEvent.raw = lword;
372                       
373                        switch (AimEvent.word.type) {
374                                case AIMTYPE_XY:
375                                        // if the datavalue is == 0, just skip it now (it can only be interpreted as type 0, obviously)
376                                        // **** I may need to decrement row here if I'm not breaking out far enough
377                                        if((lword == 0) && removeBadEvents) {
378                                                numRemoved += 1;
379                                                //sprintf(bufStr,"XOP zero at row = %d\r",row);
380                                                //XOPNotice(bufStr);
381                                                break;
382                                        }
383                                        // if it's a pileup, skip it now.
384                                        if ((AimEvent.word.ppto) && removeBadEvents) {
385                                                numRemoved += 1;
386                                                break;
387                                        }
388                                       
389                                        x = ~AimEvent.word.tildax & 127;
390                                        y = AimEvent.word.y & 127;
391                                        time_lsw = AimEvent.word.time;
392                                       
393                                        t = (double) (nRoll*rollTime + ((time_msw << 13) + time_lsw));
394
395                                        // catch the "bad" events:
396                                        // if an XY event follows a rollover, time_msw is 0 by definition, but does not immediately get
397                                        // re-evalulated here. Throw out only the immediately following points where msw is still 8191
398                                        if((rolloverHappened) && removeBadEvents) {
399                                                // maybe a bad event
400                                                if(time_msw == 8191) {
401                                                        numBad +=1;
402                                                        numRemoved += 1;
403                                                } else {
404                                                        // time_msw has been reset, points are good now, so keep this one
405                                                        ((float*)xLocPtr->waveData)[row] = (float)x;
406                                                        ((float*)yLocPtr->waveData)[row] = (float)y;
407                                                        ((double*)timePtr->waveData)[row] = (double)t;
408                                                       
409                                                        row += 1;
410                                                        rolloverHappened = 0;
411                                                }
412                                        } else {
413                                                // normal processing of good point, keep it
414                                                ((float*)xLocPtr->waveData)[row] = (float)x;
415                                                ((float*)yLocPtr->waveData)[row] = (float)y;
416                                                ((double*)timePtr->waveData)[row] = (double)t;
417                                               
418                                                row += 1;
419                                        }
420                                       
421                                        break;
422                                case AIMTYPE_XYM:               
423                                        //XY-time - save the x and y, we'll get time with the next event, a minor rollover
424                                        x = ~AimEvent.word.tildax & 127;
425                                        y = AimEvent.word.y & 127;
426                                        ((float*)xLocPtr->waveData)[row] = (float)x;
427                                        ((float*)yLocPtr->waveData)[row] = (float)y;
428                                       
429                                        time_lsw = AimEvent.word.time;
430                                       
431                                        break;
432                                case AIMTYPE_MIR:
433                                                                               
434                                        time_msw = AimEvent.word.time;
435                                        t = (double) (nRoll*rollTime + ((time_msw << 13) + time_lsw));
436
437                                        ((double*)timePtr->waveData)[row] = (double)t;
438
439                                        if (t > t_longest) t_longest = t;
440                                       
441                                        // was there a t0 signal?
442                                        if (AimEvent.word.ppto) {
443                                                // reset nRoll = 0 for calcluating the time
444                                                nRoll = 0;
445                                        }
446                                       
447                                        row += 1;
448                                       
449                                        break;
450                                case AIMTYPE_MAR:
451                                       
452                                        nRoll += 1;
453                                        rolloverHappened = 1;
454                                       
455                                        // was this major rollover also a t0 signal?
456                                        if (AimEvent.word.ppto) {
457                                                // reset nRoll = 0 for calcluating the time
458                                                nRoll = 0;
459                                        }
460                                       
461                        }               //end of the switch statement
462
463                }               //if (good data value)
464               
465        }       // while (reading lines)
466       
467
468        //
469        sprintf(bufStr,"XOP Done reading in all of the file\r");
470        XOPNotice(bufStr);
471       
472        SetOperationNumVar("V_numBad", (double)numBad);
473        SetOperationNumVar("V_numRemoved", (double)numRemoved);
474
475//      err = 0;
476//      for (row = 1; row < numRows; row++) {
477//              //if (err = XOPReadLine(fileRef, buffer, bufferLength, NULL)) {
478//              //      if (XOPAtEndOfFile(fileRef))
479//              //              err = 0;
480//              //      break;
481//              //}
482//              //bufPtr = buffer;
483//              for (column = 0; column < numColumns; column++) {
484//                      ciPtr = caPtr + column;
485//                      if(row == 1) {
486//                              sprintf(bufStr,"assigning column=%d, row = %d\r",column,row);
487//                              XOPNotice(bufStr);
488//                      }
489//                      // Store the data.
490//                      if (isDouble)
491//                              ((double*)ciPtr->waveData)[row] = 1.1; 
492//                      else {
493//                              ((float*)xLocPtr->waveData)[row] = (float)1.1;
494//                              ((float*)yLocPtr->waveData)[row] = (float)2.2;
495//                              ((float*)timePtr->waveData)[row] = (float)3.3;
496//                              //((float*)ciPtr->waveData)[row] = (float)2.2;
497//                      }
498//              }
499//              if (err)
500//                      break;
501//              SpinCursor();
502//      }
503       
504//      sprintf(bufStr,"after assignment, err = %d\r",err);
505//      XOPNotice(bufStr);
506       
507       
508        return err;
509}
510
511/*      GetWaveNames(...)
512
513        Stores a wave name for each column in the corresponding record of the
514        array pointed to by caPtr.
515       
516        If the file appears to have a row of wave names and if the user has
517        specified reading names from the file, then the names are read from
518        the file. Otherwise, the names are generated from the base name.
519
520        The file names are assumed to be on the first line, if they are present at all.
521       
522        This routine reads the names row, if there is one, leaving the file marker at
523        the start of the numeric data. If there is no names row, it does not read
524        anything from the file, so that the file marker will still be at the start
525        of the numeric data.
526       
527        Returns 0 if OK or a non-zero error code.
528*/
529static int
530GetWaveNames(
531        XOP_FILE_REF fileRef,
532        ColumnInfoPtr caPtr,
533        char* buffer, int bufferLength,
534        int numColumns,
535        int fileLoaderFlags,
536        int fileHasNamesRow,
537        const char* baseName)
538{
539        ColumnInfoPtr ciPtr;
540        int getNamesFromNamesRow;
541        char* bufPtr;
542        char ch;
543        int nameSuffix;
544        int column;
545        int i;
546        int err=0;
547
548
549        getNamesFromNamesRow = fileHasNamesRow && (fileLoaderFlags & EVENT_COUNTS_ONLY);
550        nameSuffix = -1;
551       
552        err = 0;
553        if (fileHasNamesRow) {
554                if (err = XOPReadLine(fileRef, buffer, bufferLength, NULL))
555                        return err;
556        }
557        else {
558                *buffer = 0;
559        }
560        bufPtr = buffer;
561
562        for (column = 0; column < numColumns; column++) {
563                ciPtr = caPtr + column;
564                if (getNamesFromNamesRow) {
565                        for (i = 0; i < 256; i++) {                                     // Column name assumed never longer than 256.
566                                ch = *bufPtr++;
567                                if (ch == 0)
568                                        break;
569                                if (strchr(gSeparatorsStr, ch))                 // Tab or comma separates one column from the next.
570                                        break;
571                                if (i < MAX_OBJ_NAME)
572                                        ciPtr->waveName[i] = ch;
573                        }
574                        if (err)
575                                break;                                                                  // File manager error.
576                }
577                else {          // Use default names.
578                        if (fileLoaderFlags & FILE_LOADER_OVERWRITE) {
579                                sprintf(ciPtr->waveName, "%s%lld", baseName, (SInt64)column);
580                        }
581                        else {
582                                nameSuffix += 1;
583                                if (err = UniqueName2(MAIN_NAME_SPACE, baseName, ciPtr->waveName, &nameSuffix))
584                                        return err;
585                        }
586                }
587       
588                SanitizeWaveName(ciPtr->waveName, column);              // Make sure it is a proper wave name.
589        }
590       
591        return err;
592}
593
594/*      GetWaveNameList(caPtr, numColumns, waveNamesHandle)
595
596        Stores semicolon-separated list of wave names in waveNamesHandle with
597        a null terminating character at the end. This is used to set the
598        Igor variable S_waveNames via SetFileLoaderOperationOutputVariables.
599*/
600static int
601GetWaveNameList(ColumnInfoPtr caPtr, CountInt numColumns, Handle waveNamesHandle)
602{
603        ColumnInfoPtr ciPtr;
604        char* p;
605        int waveNamesLen;
606        int column;
607       
608        waveNamesLen = 0;
609        for (column = 0; column < numColumns; column++) {
610                ciPtr = caPtr + column;
611                if (ciPtr->waveHandle != NULL)                                          // We made a wave for this column ?
612                        waveNamesLen += (int)strlen(ciPtr->waveName)+1; // +1 for semicolon.
613        }
614        SetHandleSize(waveNamesHandle, waveNamesLen+1);                 // +1 for null char at end.
615        if (MemError())
616                return NOMEM;
617
618        p = *waveNamesHandle;           // DEREFERENCE -- we must not scramble heap.
619        for (column = 0; column < numColumns; column++) {
620                ciPtr = caPtr + column;
621                if (ciPtr->waveHandle != NULL) {                                        // We made a wave for this column ?
622                        strcpy(p, ciPtr->waveName);
623                        p += strlen(ciPtr->waveName);
624                        *p++ = ';';
625                }
626        }
627        *p = 0;                                         // Add null char.
628
629        return 0;
630}
631
632/*      LoadEvent(fileRef, baseName, fileLoaderFlags, wavesLoadedPtr, waveNamesHandle)
633       
634        Loads a simple tab-delimited TEXT file and returns error code.
635        fileRef is the file reference for the file to be loaded.
636        baseName is base name for new waves.
637        fileLoaderFlags contains bit flags corresonding to flags the user
638        supplied to the XOP.
639       
640        Sets *wavesLoadedPtr to the number of waves succesfully loaded.
641        Stores in waveNamesHandle a semicolon-separated list of wave names
642        with a null character at the end.
643        *wavesLoadedPtr is initially a handle with 0 bytes in it.
644*/
645static int
646LoadEvent(
647        XOP_FILE_REF fileRef,
648        const char* baseName,
649        int fileLoaderFlags,
650        int* wavesLoadedPtr,
651        Handle waveNamesHandle)
652{
653        CountInt numRows;                       //this is a not a normal value -- see FindNumberOfRows
654        int numColumns;
655        int column;                                                                     // Current column.
656        int fileHasNamesRow;                                            // Truth file has column names.
657        ColumnInfoPtr caPtr;                                            // Pointer to an array of records, one for each column. See EventLoadWave.h.
658        ColumnInfoPtr ciPtr;                                            // Pointer to the record for a specific column.
659        char* buffer;
660        int bufferLength;
661        int err;
662        char bufStr[500];               //to print
663        // for the file scan
664        char buf[128];          //TB
665        unsigned int lword;
666        int scanOnly;
667       
668        caPtr = NULL;
669        bufferLength = 20000;                   // This is an arbitrary choice of maximum line length.
670        buffer = (char*)NewPtr(bufferLength);
671        if (buffer == NULL)
672                return NOMEM;
673       
674        *wavesLoadedPtr = 0;
675
676        // Find number of columns of data.
677//      if (err = FindNumberOfColumns(fileRef, buffer, bufferLength, &numColumns))
678//              goto done;
679
680        numColumns = 3;         //force this to three (only because I want 3 output waves of my naming scheme
681       
682       
683//      // Determine if file has column names.
684//      if (err = XOPReadLine(fileRef, buffer, bufferLength, NULL))
685//              goto done;
686//      // File assumed to have column names if first char is alphabetic - a very simple-minded test.
687//      fileHasNamesRow = isalpha(*buffer);
688        fileHasNamesRow = 0;            //force this to false
689
690        XOPSetFilePosition2(fileRef, 0);                                                // Go back to start of first row.
691               
692        // Make data structure used to input columns.
693        caPtr = (ColumnInfoPtr)NewPtr(numColumns*sizeof(ColumnInfo));
694        if (caPtr == NULL) {
695                err = NOMEM;
696                goto done;
697        }
698        MemClear((char *)caPtr, numColumns*sizeof(ColumnInfo)); 
699       
700        err = GetWaveNames(fileRef, caPtr, buffer, bufferLength, numColumns, fileLoaderFlags, fileHasNamesRow, baseName);
701        if (err)                                                                                                // Error reading names ?
702                goto done;
703       
704        // GetWaveNames leaves the file marker pointing to the numeric data.
705
706        scanOnly = fileLoaderFlags & EVENT_COUNTS_ONLY;
707// do a scan of the file to get the counts
708        // zero the counter
709        counter.XYevents = 0;
710        counter.num0 = 0;
711        counter.num1 = 0;
712        counter.num2 = 0;
713        counter.num3 = 0;
714        counter.zeros = 0;
715        counter.t0 = 0;
716        counter.major_rollover = 0;
717        counter.minor_rollover = 0;
718        counter.pp = 0;
719        counter.dl = 0;         
720       
721        //process all of the events, one-by one, here I'm just getting the counts
722        while(fgets(buf,sizeof(buf),fileRef)) {
723                if (sscanf(buf,"%x",&lword)) {
724                        ScanEvents(lword);
725                }
726        }
727       
728        SetOperationNumVar("V_nXYevents", (double)counter.XYevents);
729        SetOperationNumVar("V_num0", (double)counter.num0);
730        SetOperationNumVar("V_num1", (double)counter.num1);
731        SetOperationNumVar("V_num2", (double)counter.num2);
732        SetOperationNumVar("V_num3", (double)counter.num3);
733        SetOperationNumVar("V_numT0", (double)counter.t0);
734        SetOperationNumVar("V_numPP", (double)counter.pp);
735        SetOperationNumVar("V_numZero", (double)counter.zeros);
736       
737        sprintf(bufStr,"V_nXYevents = %d\r",counter.XYevents);
738        XOPNotice(bufStr);
739
740        if(scanOnly) {
741                //close the file before leaving? - nope, LoadWave() wll do this on exit from here
742                sprintf(bufStr,"Scan only...No event processing\r");
743                XOPNotice(bufStr);
744                return(0);                      //get out before any waves are generated
745        }
746       
747       
748        /// not just a scan, now I have the counts, etc.
749        XOPSetFilePosition2(fileRef, 0);                                                // Go back to start of first row.
750       
751        // Find number of rows in the file.
752//      if (err = FindNumberOfRows(fileRef, buffer, bufferLength, &numRows))
753//              goto done;
754//      if (numRows < 1) {
755//              err = NO_DATA_FOUND;
756//              goto done;
757//      }
758
759        numRows = (CountInt)counter.XYevents;
760       
761//      sprintf(bufStr,"numCol = %d, numRows = %lld\r",numColumns,(SInt64)numRows);
762//      XOPNotice(bufStr);
763       
764// from the manual for the MakeWave utility - integer types are only recommended for storage when there
765        // is a great need to save space (there is here) - but that integers are internally translated into FP values
766        // for any display or analysis. So just leave them as-is here, as FileLoaderMakeWave generates
767        // Make wave for each column.
768        for (column = 0; column < numColumns; column++) {
769                ciPtr = caPtr + column;
770                ciPtr->waveAlreadyExisted = FetchWave(ciPtr->waveName) != NULL;
771                if (column==0 || column == 1) {
772                        // columns 0 and 1 are
773                        err = FileLoaderMakeWave(column, ciPtr->waveName, numRows, fileLoaderFlags, &ciPtr->waveHandle);
774                } else {
775                        // column 2 is the time, and needs to be DP
776                        err = FileLoaderMakeWave(column, ciPtr->waveName, numRows, (fileLoaderFlags | FILE_LOADER_DOUBLE_PRECISION), &ciPtr->waveHandle);
777                }
778
779//              sprintf(bufStr,"make wave = %d\r",column);
780//              XOPNotice(bufStr);
781                if (err) {
782                        sprintf(bufStr,"FileLoaderMakeWave returned an error  numCol = %d, numRows = %lld\r",numColumns,(SInt64)numRows);
783                        XOPNotice(bufStr);
784                        break;          // NOTE: In this case, not all fields in caPtr are set.
785                }
786        }
787       
788        if (err == 0) {
789                // Lock wave handles and get pointers to wave data.
790                for (column = 0; column < numColumns; column++) {
791                        ciPtr = caPtr + column;
792                        ciPtr->waveData = WaveData(ciPtr->waveHandle);          // ciPtr->waveData is now valid because the wave is locked.
793                }
794       
795//              sprintf(bufStr,"Waves locked, ready to load\r");
796//              XOPNotice(bufStr);
797               
798                // Load data. This is where the work is done
799                err = LoadEventData(fileRef, buffer, bufferLength, fileLoaderFlags, caPtr, numRows, numColumns);
800        }
801       
802        if (err==0) {
803                // Clean up waves.
804                for (column = 0; column < numColumns; column++)
805                        FinishWave(caPtr + column, fileLoaderFlags);
806                *wavesLoadedPtr = numColumns;
807        }
808        else {
809                // Error occurred - kill any waves that we created.
810                for (column = 0; column < numColumns; column++) {
811                        ciPtr = caPtr + column;
812                        if (ciPtr->waveHandle && !ciPtr->waveAlreadyExisted) {  // We made a wave for this column ?
813                                KillWave(ciPtr->waveHandle);
814                                ciPtr->waveHandle = NULL;
815                        }
816                }
817        }
818                       
819        // Get semicolon-separated list of wave names used below for SetFileLoaderOperationOutputVariables.
820        if (err == 0)
821                err = GetWaveNameList(caPtr, numColumns, waveNamesHandle);
822
823done:
824        if (buffer != NULL)
825                DisposePtr(buffer);
826        if (caPtr != NULL)
827                DisposePtr((Ptr)caPtr);
828       
829        return err;
830}
831
832/*      GetLoadFile(initialDir, fullFilePath)
833
834        GetLoadFile puts up a standard open dialog to get the name of the file
835        that the user wants to open.
836       
837        initialDir is a full path to the directory to initially display in the
838        dialog or "" if you don't care.
839       
840        It returns -1 if the user cancels or 0 if the user clicks Open.
841        If the user clicks Open, returns the full path via fullFilePath.
842*/
843static int
844GetLoadFile(const char* initialDir, char* fullFilePath)
845{
846        #ifdef MACIGOR
847                const char* filterStr = "Data Files:TEXT:.dat;All Files:****:;";
848        #endif
849        #ifdef WINIGOR
850                const char* filterStr = "Data Files (*.dat)\0*.dat\0All Files (*.*)\0*.*\0\0"; 
851        #endif
852        char prompt[80];
853        int result;
854       
855        static int fileIndex = 2;               // This preserves the setting across invocations of the dialog. A more sophisticated XOP would save this as a preference.
856
857        *fullFilePath = 0;                              // Must be preset to zero because on Windows XOPOpenFileDialog passes this to GetOpenFileName which requires that it be preset.
858       
859        strcpy(prompt, "Looking for a tab or comma-delimited file");
860        result = XOPOpenFileDialog(prompt, filterStr, &fileIndex, initialDir, fullFilePath);
861
862        return result;
863}
864
865/*      LoadWave(calledFromFunction, flags, baseName, symbolicPathName, fileParam)
866
867        LoadWave loads data from the tab-delimited file specified by symbolicPathName and fileParam.
868       
869        calledFromFunction is 1 if we were called from a user function, zero otherwise.
870       
871        flags contains bits set based on the command line flags that were
872        used when the command was invoked from the Igor command line or from a macro.
873       
874        baseName is the base name to use for new waves if autonaming is enabled by fileLoaderFlags.
875       
876        It returns 0 if everything goes OK or an error code if not.
877*/
878int
879LoadWave(int calledFromFunction, int fileLoaderFlags, const char* baseName, const char* symbolicPathName, const char* fileParam)
880{
881        char symbolicPathPath[MAX_PATH_LEN+1];          // Full path to the folder that the symbolic path refers to. This is a native path with trailing colon (Mac) or backslash (Win).
882        char nativeFilePath[MAX_PATH_LEN+1];            // Full path to the file to load. Native path.
883        Handle waveNamesHandle;
884        int wavesLoaded;
885        XOP_FILE_REF fileRef;
886        int err;
887
888        *symbolicPathPath = 0;
889        if (*symbolicPathName != 0) {
890                if (err = GetPathInfo2(symbolicPathName, symbolicPathPath))
891                        return err;
892        }
893       
894        if (GetFullPathFromSymbolicPathAndFilePath(symbolicPathName, fileParam, nativeFilePath) != 0)
895                fileLoaderFlags |= FILE_LOADER_INTERACTIVE;             // Need dialog to get file name.
896               
897        if (!FullPathPointsToFile(nativeFilePath))                      // File does not exist or path is bad?
898                fileLoaderFlags |= FILE_LOADER_INTERACTIVE;             // Need dialog to get file name.
899
900        if (fileLoaderFlags & FILE_LOADER_INTERACTIVE) {
901                if (GetLoadFile(symbolicPathPath, nativeFilePath))
902                        return -1;                                                      // User cancelled.
903        }
904       
905        TellFileType("Event file load from", nativeFilePath, fileLoaderFlags);
906       
907        if (err = SetFileLoaderOperationOutputVariables(calledFromFunction, nativeFilePath, 0, ""))     // Initialize Igor output variables.
908                return err;
909       
910        // Open file.
911        if (err = XOPOpenFile(nativeFilePath, 0, &fileRef))
912                return err;
913       
914        waveNamesHandle = NewHandle(0L);        // Will contain semicolon-separated list of wave names.
915        WatchCursor();
916        err = LoadEvent(fileRef, baseName, fileLoaderFlags, &wavesLoaded, waveNamesHandle);
917        XOPCloseFile(fileRef);
918        ArrowCursor();
919       
920        // Store standard file loader output globals.
921        if (err == 0)
922                err = SetFileLoaderOperationOutputVariables(calledFromFunction, nativeFilePath, wavesLoaded, *waveNamesHandle);
923
924        DisposeHandle(waveNamesHandle);
925       
926        return err;
927}
928
929/*      XOPMenuItem()
930
931        XOPMenuItem is called when the XOP's menu item is selected.
932*/
933static int
934XOPMenuItem(void)
935{
936        char filePath[MAX_PATH_LEN+1];                          // Room for full file specification.
937        int fileLoaderFlags;
938        int err;
939
940        if (GetLoadFile("", filePath))
941                return 0;                                                               // User cancelled.
942       
943        fileLoaderFlags = EVENT_COUNTS_ONLY | FILE_LOADER_DOUBLE_PRECISION;
944        err = LoadWave(0, fileLoaderFlags, "wave", "", filePath);
945        return err;
946}
947
948/*      XOPEntry()
949
950        This is the entry point from the host application to the XOP when the message specified by the
951        host is other than INIT.
952*/
953extern "C" void
954XOPEntry(void)
955{       
956        XOPIORecResult result = 0;
957       
958        switch (GetXOPMessage()) {
959                case CLEANUP:                                                           // XOP about to be disposed of.
960                        break;
961
962                case MENUITEM:                                                          // XOPs menu item selected.
963                        result = XOPMenuItem();
964                        SetXOPType(TRANSIENT);                                  // XOP is done now.
965                        break;
966        }
967       
968        SetXOPResult(result);
969}
970
971/*      main()
972
973        This is the initial entry point at which the host application calls XOP.
974        The message sent by the host must be INIT.
975       
976        main does any necessary initialization and then sets the XOPEntry field of the
977        XOPRecHandle to the address to be called for future messages.
978*/
979HOST_IMPORT int
980XOPMain(IORecHandle ioRecHandle)
981{
982        int err;
983       
984        XOPInit(ioRecHandle);                           // Do standard XOP initialization.
985        SetXOPEntry(XOPEntry);                          // Set entry point for future calls.
986
987        if (igorVersion < 620) {                        // Requires Igor Pro 6.20 or later.
988                SetXOPResult(OLD_IGOR);                 // OLD_IGOR is defined in EventLoadWave.h and there are corresponding error strings in EventLoadWave.r and EventLoadWaveWinCustom.rc.
989                return EXIT_FAILURE;
990        }
991       
992        if (err = RegisterEventLoadWave()) {
993                SetXOPResult(err);
994                return EXIT_FAILURE;
995        }
996
997        SetXOPResult(0);
998        return EXIT_SUCCESS;
999}
Note: See TracBrowser for help on using the repository browser.