#import "SegmentManagerThreads.h"
#import <stdlib.h>

@implementation SegmentManager (Threads)

static void
getThreadInfo(ThreadInfo *tInfo, struct thread_command *tCmd)
{
    struct thread_state {
	unsigned long flavor;
	unsigned long countcount;
	unsigned long state[0];
    } *threadState;
    int size;
    
    for (size = tCmd->cmdsize - sizeof(struct thread_command), 
         threadState = (struct thread_state *)(tCmd + 1);
#ifdef GDB_HPPA
         size > 0;
#else
         size;
#endif GDB_HPPA
	 size -= (sizeof(struct thread_state)
	          + (threadState->countcount * sizeof(unsigned long))),
	 threadState
	 = (struct thread_state *)(threadState->state
	                           + threadState->countcount)) {
#ifdef GDB_HPPA
	if (threadState->flavor == REGS_STATE)
	    tInfo->frameRegs = (REGS_STRUCT *)&threadState->state;
	else if (threadState->flavor == FP_REGS_STATE)
	    tInfo->fpRegs = (FP_REGS_STRUCT *)&threadState->state;
	else if (threadState->flavor == USER_REG_STATE)
	    tInfo->intRegs = (USER_REG_STRUCT *)&threadState->state;
#else
	if (threadState->flavor == REGS_STATE)
	    tInfo->intRegs = (REGS_STRUCT *)&threadState->state;
	else if (threadState->flavor == FP_REGS_STATE)
	    tInfo->fpRegs = (FP_REGS_STRUCT *)&threadState->state;
	else if (threadState->flavor == USER_REG_STATE)
	    tInfo->userReg = (USER_REG_STRUCT *)&threadState->state;
#endif GDB_HPPA
#ifdef GDB_88K
	else if (threadState->flavor == M88110_THREAD_STATE_IMPL)
	    tInfo->implRegs 
	    = (struct _m88110_thread_state_impl *)threadState->state;
#endif GDB_88K	    
    }
}

-(int)numThreads
{
    int nImages, nInfos = 0;
    Image *image;

    for (nImages = numImages, image = images;
         nImages;
	 nImages--, image++) {
	nInfos += [self numCommands: LC_THREAD forHeader: image->header];
	nInfos += [self numCommands: LC_UNIXTHREAD forHeader: image->header];
    }
    return nInfos;
}

-(ThreadInfo *)threadInfos
{
    int nImages, nInfos;
    struct load_command *loadCmd;
    ThreadInfo *infos, *info;
    Image *image;
    
    nInfos = [self numThreads];
    info = infos = calloc(nInfos,sizeof(ThreadInfo));
    for (nImages = numImages, image = images;
         nImages;
	 nImages--, image++) {
	for (loadCmd = (struct load_command *)(image->header + 1);
	     nInfos;
	     ((void *)loadCmd) += loadCmd->cmdsize) {
	    if ((loadCmd->cmd == LC_THREAD)
	        || (loadCmd->cmd == LC_UNIXTHREAD)) {
		getThreadInfo(info,  (struct thread_command *)loadCmd);
		info++;
		nInfos--;
	    }
	}
    }
    return infos;
}

-(BOOL)threadInfo: (ThreadInfo *)tInfo forThreadNum: (int)tNum
{
    int nImages, nCmds;
    struct load_command *loadCmd;
    Image *image;
    
    for (nImages = numImages, image = images;
         nImages;
	 nImages--, image++) {
	for (nCmds = image->header->ncmds,
	     loadCmd = (struct load_command *)(image->header + 1);
	     nCmds;
	     nCmds--, ((void *)loadCmd) += loadCmd->cmdsize) {
	    if ((loadCmd->cmd == LC_THREAD)
		|| (loadCmd->cmd == LC_UNIXTHREAD)) {
		if (!tNum) {
		    getThreadInfo(tInfo,  (struct thread_command *)loadCmd);
		    return YES;
		} else
		    tNum--;
	    }
	}
    }
    return NO;
}

@end
