ftp.nice.ch/pub/next/developer/apps/Eval.3.3.s.tar.gz#/Eval3.3/support.m

This is support.m in view mode; [Download] [Up]

/**
 ** support.m
 **
 ** supporting functions for Eval
 **/

#import <objc/objc-load.h> 
#import <sys/fcntl.h>
#import <sys/file.h>
#import <dpsclient/psops.h>
#import <dpsclient/dpsclient.h>
#import <stdlib.h>
#import <strings.h>
#import <bsd/libc.h>
#import <sys/dir.h>
#import <sys/file.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <objc/List.h>
#import "Eval.h"
#import "EvalString.h"
#import "EvalWrap.h"



int classNames(const char *filePath, const char **buf) 
{ // Assumes filePath is the path to a .o file  containing a class definition. 
  // Sets buf to point to a string containing the name of all classes
  // defined in the module, in the form
  //    className1:superclassName1 className2(category)
  // The string buf "belongs to" this procedure, and shouldn't be
  // altered in any way.  It is only valid until the next call
  // to superClassName.
  struct mach_header mh ;
  struct segment_command sc ;
  struct section sect ;
  struct objc_class oc_cl ;
  struct objc_category oc_ca ;
  static NXStream *aStream = NULL ;
  int fn,i,j,k,unused ;
  off_t saveLoadLoc, saveSegLoc ;
  char c ;
  if(!aStream)
    aStream = NXOpenMemory(NULL, 0, NX_WRITEONLY) ; 
  else
    NXSeek(aStream,0,NX_FROMSTART) ;
  if((fn = open(filePath, O_RDONLY)) < 0)
    return 0 ;
  lseek(fn, 0l, 0) ;
  if(read(fn,&mh,sizeof(struct mach_header)) < sizeof(struct mach_header))
    return 0  ; // short file
  for(i = 0 ; i < mh.ncmds ; i++) // for each load command
  { if(read(fn,&sc,sizeof(struct load_command)) < sizeof(struct load_command))
       return 0 ; // short file
    saveLoadLoc = lseek(fn,0,L_INCR) ;
    if(sc.cmd != LC_SEGMENT) // not a segment command, skip it
      if(lseek(fn, sc.cmdsize - sizeof(struct load_command) ,L_INCR) == -1)
        return 0 ; // can't seek
    else // segment command...get rest of header
    { if(read(fn,&sc.segname,sizeof(struct segment_command) - 
           sizeof(struct load_command)) < sizeof(struct segment_command) - 
           sizeof(struct load_command))
         return 0 ; // short file
      else
      { for(j = 0 ; j < (sc.nsects) ; j++) // for each segment header
        { if(read(fn,&sect,sizeof(struct section)) < sizeof(struct section))
            return 0 ; // short file ;
          saveSegLoc = lseek(fn,0,L_INCR) ;
          if(!strcmp(sect.segname, SEG_OBJC)) 
          { // found an objc segement...look for class or category section

            if(!strcmp(sect.sectname,"__class"))
            { // we've found an objc class section 
              for(k = 0 ; k < (sect.nreloc/3)  ;k++) 
              { // Examine each  relocation entry (making the assumption that
                // their length is sizeof(struct objc_class)).  I know empirically that
                // that class generates 3 relocation entries, and that the entries we
                // are interested in appear first, hence sect.nreloc/3.
                if(lseek(fn,sect.offset + (k * sizeof(struct objc_class)),L_SET) == -1)
                   return 0 ; // can't seek
                if(read(fn,&oc_cl,sizeof(struct objc_class)) // read in the objc_class structure
                   < sizeof(struct objc_class))
                  return 0 ; // short file
                if(CLS_GETINFO(&oc_cl,CLS_CLASS))
                { if(lseek(fn,mh.sizeofcmds + (long int) oc_cl.name +
                      sizeof(struct mach_header), L_SET) == -1)
                    return 0 ; // can't seek
                  while(read(fn,&c,1))
                  { if(c)
                      NXPutc(aStream,c) ;
                    else
                    { NXPutc(aStream,':') ;
                      break ;
                    }
                  }
                  if(lseek(fn,mh.sizeofcmds  + (long int) oc_cl.super_class +
                    sizeof(struct mach_header), L_SET) == -1)
                    return 0 ; // can't seek
                  while(read(fn,&c,1))
                  { if(c)
                     NXPutc(aStream,c) ;
                    else
                    { NXWrite(aStream,"   ",3) ;
                      break ;
                    }
                  }
                }            
              }
            }

            else if(!strcmp(sect.sectname,"__category"))
            { // we've found an objc category section
              for(k = 0 ; k < (sect.nreloc >> 1)  ; k++ ) 
              { // examine each  relocation entry (making the assumption that
                // their length is sizeof(struct objc_category)).  I know empirically that
                // each category generates 2 relocation entries, and that the entries we
                // are interested in appear first, hence sect.nreloc >> 1.
                if(lseek(fn,sect.offset + (k * sizeof(struct objc_category)),L_SET) == -1)
                   return 0 ; // can't seek
                if(read(fn,&oc_ca,sizeof(struct objc_category)) // read in the objc_category structure
                   < sizeof(struct objc_category))
                  return 0 ; // short file               
                { if(lseek(fn,mh.sizeofcmds + (long int) oc_ca.class_name +
                      sizeof(struct mach_header), L_SET) == -1)
                    return 0 ; // can't seek
                  while(read(fn,&c,1)) // read in class name
                  { if(c)
                      NXPutc(aStream,c) ;
                    else
                    { NXPutc(aStream,'(') ;
                      break ;
                    }
                  }
                  if(lseek(fn,mh.sizeofcmds  + (long int) oc_ca.category_name +
                    sizeof(struct mach_header), L_SET) == -1)
                    return 0 ; // can't seek
                  while(read(fn,&c,1)) // read in category name
                  { if(c)
                     NXPutc(aStream,c) ;
                    else
                    { NXWrite(aStream,")   ",4) ;
                      break ;
                    }
                  }
                }              
              }
            }
          }
          lseek(fn,saveSegLoc,L_SET) ;
        }
      }
    }
    lseek(fn,saveLoadLoc,L_SET) ;
  }
  close(fn) ;
  NXPutc(aStream,'\0') ;
  NXGetMemoryBuffer(aStream,buf,&unused,&unused) ;
  return 1 ;
}

void setSelectionRange(NXSelPt *start, NXSelPt *end, int length)
{ // check that start and end "make sense", and if start == end,
  // set them to embrace entire text, from 0 to length. 
  if((start->cp < 0) || (start->cp > length))
    start->cp = 0 ;
  if((end->cp <0) || (end->cp > length))
    end->cp = 0 ;
  if(start->cp >= end->cp)
  {  start->cp = 0 ;
      end->cp = length ;
  }
}


BOOL EvalGets(NXStream *aStream, char * aBuf)
{ // Procedure to get the next line (or remainder of
  // stream) from a stream. The newline is discarded.  
  // If newline is present, returns YES, else if instead
  // the end of stream is found, returns NO (but aBuf may
  // still contain data).
  int c,i = 0;
  c = NXGetc(aStream) ;
  do
  { if(c == -1) // end of stream
    { aBuf[i] = '\0' ;
      return NO ;
    }
    else if(c == '\n')
    { aBuf[i] = '\0' ;
      return YES ;
    }
    else
    { aBuf[i++] = (char) c ;
      c = NXGetc(aStream) ;
    } 
  } while(1) ;
}

BOOL mkTempFile(char *path, char *fileName)
{ // fileName should contain eight trailing X's.
  // Make a "temporary" file.  Similar to mktemp, but 
  // not only ensures that the filename is unique, but 
  // also that there is no filename with the same prefix.
  // i.e. if fileName is set to FooXXXXXXXX, you are assured 
  // that no files match FooXXXXXXXX*.  If path is
  // nonNull, than fileName is unique within the directory
  // path.  Else is path is null, than fileName is assumed
  // to contain the complete path. The temporary file name
  // is placed "in" fileName. Returns YES on success, NO if
  // can't create the file.

  char *thePath, *lastSlash = NULL ;
  int i,fileNameIndex = 0, fileIndex = 0, 
      oldFileNameLen, newFileNameLen, fileCount ;
  int pid = getpid() ;
  static int maxFileIndex = 1000 ;
  static int XCount = 8 ; // how many X's at end of filename
  struct direct **filesList ;
  if(path)
    thePath = path ;
  else
  { lastSlash = strrchr(fileName,'/') ;
    if(lastSlash)
    { fileNameIndex = lastSlash - fileName + 1 ; // index of beginning of fileName
      thePath = (char *) malloc(fileNameIndex + 1) ;
      strncpy(thePath,fileName,fileNameIndex - 1) ;
      thePath[fileNameIndex - 1] = '\0' ;
    }
    else // search current directory
      thePath = "." ;  
  }
  oldFileNameLen = strlen(&fileName[fileNameIndex]) ;
  do
  { // create a candidate file name
    sprintf(&fileName[fileNameIndex + oldFileNameLen - XCount],"%d%d",pid,fileIndex++) ;
    newFileNameLen = strlen(&fileName[fileNameIndex]) ;
    // check if its unique. 
    fileCount = scandir(thePath,&filesList,NULL,NULL) ;
    if(fileCount == -1)
      break ;
    for(i = 0 ; i < fileCount ; i++)
    { if(!strncmp(&fileName[fileNameIndex],(*filesList[i]).d_name,newFileNameLen))
        break ; 
    }
    if(i == fileCount)
      break ; // no conflicts found: go with name
  } while(fileIndex < maxFileIndex) ;
  if(lastSlash)
    free(thePath) ;
  if((fileCount == -1) || (fileIndex == maxFileIndex))
    return NO ;
  return YES ;
}

void SwitchContextsWithFocus(DPSContext newContext)
{ // borowsed from YAP: switch to newContext in order to
  // ``protect'' the main context
  float c1x, c1y, c2x, c2y;
  float winCTM[6];
  int realWinNum;
  GetFocus(&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum);
  DPSSetContext(newContext);
  ReFocus(realWinNum, winCTM, c1x, c1y, c2x, c2y);
}

List *tmpFileList(char *path)
{ // Creates and returns a list of "temporary file names" in
  // directory "path". These are files which match path/EvalXXXXXXXX,
  // (where the X's are replaced by the process id of current process).
  // In other words,  files which were created by mkTempFile() in this
  // process. This will be a list of EvalStrings, each of which contains
  // the full path of each such file. It is the callers responsibility
  // to free these EvalStrings and the List (although, in normal usage,
  // this is never done, because this procedure is called by 
  // from Eval::appWillTerminate in order to clean up before exiting).
  int i,len,fileCount ;
  struct direct **filesList ;
  List *aList = [List new] ;
  char *fullPath ;
  char fileName[20] ;
  sprintf(fileName,"Eval%d",getpid()) ;
  [Eval printf: "%s\n",fileName] ;
  len = strlen(fileName) ;
  fullPath = (char *) alloca(strlen(path) + len + 256) ;
  fileCount = scandir(path,&filesList,NULL,NULL) ;
  for(i = 0 ; i < fileCount ; i++)
  { if(!strncmp(fileName,(*filesList[i]).d_name,len))
    { sprintf(fullPath,"%s/%s",path,(*filesList[i]).d_name) ;
      [aList addObject: [EvalString new: fullPath]] ;
    }
  }
  return aList ;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.