This is Controller.m in view mode; [Download] [Up]
//
// This is the Compiler's Companion a program to integrate make's and Edit
// more cleanly. Version 2.0
//
// Copyright(C) 1992 Daryll Strauss
//
// This program is shareware; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 1, or (at your option)
// any later version as long as you leave all the references to the fact
// that it is shareware and covered by the GNU General Public License in
// tact.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// Please see the README.rtf file for more details on the shareware
// distribution and the GNU General Public License.
//
#import "Controller.h"
#import <stdio.h>
#import <stdlib.h>
#import <strings.h>
#import <mach_init.h>
#import <mach_interface.h>
#import <streams/streams.h>
#import <sys/file.h>
#import <dpsclient/dpsclient.h>
#import <appkit/nextstd.h>
#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <appkit/Application.h>
#import <appkit/Listener.h>
#import <appkit/Speaker.h>
#import <appkit/Panel.h>
#import <appkit/Form.h>
#import <appkit/Pasteboard.h>
#import <appkit/Panel.h>
#import <appkit/OpenPanel.h>
#import "Defaults.h"
#define DISPLAY_ERROR(msg) [self sysError:msg :__FILE__ :__LINE__]
@implementation Controller
static char *directory;
static char *command;
static char *good_cmd;
static char *bad_cmd;
static BOOL pref_services;
static BOOL pref_pref_dir;
static BOOL hide_on_success;
static char *file;
static BOOL prompt_User=TRUE;
static BOOL Aux_Loaded=FALSE;
static int end_pos;
static BOOL Make_In_Progress=FALSE;
Full_Defaults_Vector CompilerDefaults[] = {
{default_string, "directory", "", &directory},
{default_const_string, "command", "make -k", &command},
{default_bool, "services", "Yes", &pref_services},
{default_bool, "usePrefDir", "No", &pref_pref_dir},
{default_bool, "hideOnSuccess", "No", &hide_on_success},
{default_string, "executeGood", "sndplay ~/Apps/Compiler.app/good.snd &",
&good_cmd},
{default_string, "executeBad", "sndplay ~/Apps/Compiler.app/bad.snd &",
&bad_cmd},
{default_end, 0, 0, 0}
};
//
// Basic support functions
//
void set_directory(char *new_dir)
{
if (directory) free(directory);
directory=malloc(strlen(new_dir)+1);
strcpy(directory, new_dir);
}
void set_file(char *new_file)
{
if (file) free(file);
file=malloc(strlen(new_file)+1);
strcpy(file, new_file);
}
int Find_Newline(NXStream *data, int direction)
{
int pos;
if (direction==1) {
while (!NXAtEOS(data))
if (NXGetc(data)=='\n') return(1);
return(0);
} else {
pos=NXTell(data);
while (pos>0) {
NXSeek(data, pos, NX_FROMSTART);
if (NXGetc(data)=='\n') return(1);
pos--;
}
return(0);
}
}
int parse_error(NXStream *data, char **file, int *line)
{
int file_pos, line_pos, i;
char *filename, c=0;
file_pos=NXTell(data);
while (!NXAtEOS(data)) {
c=NXGetc(data);
if (c=='\n') return(0);
if (c==' ') return(0);
if (c==':') break;
}
if (c!=':') return(0);
line_pos=NXTell(data);
filename=*file=malloc(line_pos-file_pos);
NXSeek(data, file_pos, NX_FROMSTART);
for (i=0; i<line_pos-file_pos-1; i++) {
*filename=NXGetc(data);
filename++;
}
*filename=0;
NXGetc(data);
*line=(-1);
while (!NXAtEOS(data)) {
c=NXGetc(data);
if (c==':' || c=='\n') break;
if (c<'0' || c>'9') {
free(*file);
Find_Newline(data, 1);
return(0);
} else {
if (*line==-1) *line=0;
*line=10*(*line)+c-'0';
}
}
if ((c=='\n') || (*line==-1)) {
free(*file);
return(0);
}
return(1);
}
//
// Object support functions
//
- (void)sysError:(char *)msg :(char *)file :(int)line
{
NXRunAlertPanel("System Error", "A system error occurred.\nThis should never happen.\nPlease include this in your bug report:\nVersion %s -- %s at %s:%d", "Sorry",
0, 0, __DATE__, msg, file, line);
}
- (const char *)Find_Lost_File:(const char *)file;
{
OpenPanel *op;
op = [[OpenPanel new] allowMultipleFiles:FALSE];
[op setAccessoryView:locate];
if ([op runModal]) return([op filename]);
return(0);
}
- (void)positionOnFile:(const char *)filename Line:(int)line
{
port_t edit_port;
int completed;
char position[100];
if ((edit_port=NXPortFromName("Edit", 0))==PORT_NULL) {
DISPLAY_ERROR("Finding port");
return;
}
if (access(filename, R_OK)<0) { /* We can't find or open the given file */
filename=[self Find_Lost_File:filename];
if (!filename) {
NXRunAlertPanel(0, "Couldn't find the file from the error message",
0, 0, 0);
return;
}
}
[[NXApp appSpeaker] setSendPort:edit_port];
if (![[NXApp appSpeaker] sendOpenFileMsg:filename ok:&completed
andDeactivateSelf:TRUE]) {
if (!completed) {
NXRunAlertPanel(0, "Edit couldn't open file %s\n", 0, 0, 0,
filename);
return;
}
} else {
DISPLAY_ERROR("Sending open");
return;
}
sprintf(position, "%d:%d", line, line);
if (![[NXApp appSpeaker] msgSetPosition:position posType:NX_LINENUMPOSTYPE
andSelect:TRUE ok:&completed]) {
if (!completed) {
NXRunAlertPanel(0, "Edit couldn't position the file at line %d\n",
0, 0, 0, line);
return;
}
} else {
DISPLAY_ERROR("Sending position");
return;
}
}
- (void)loadAux
{
if (!Aux_Loaded) {
[NXApp loadNibSection:"Auxillary.nib" owner:self];
Aux_Loaded=TRUE;
}
}
- appDidInit:sender
{
Register_Full_Defaults("Compiler", CompilerDefaults);
directory=0;
Get_Full_Defaults("Compiler", CompilerDefaults);
[cmd_form setStringValue:directory at:0];
[cmd_form setStringValue:command at:1];
[[NXApp appListener] setServicesDelegate:self];
NXSetServicesMenuItemEnabled("Compiler/Make", pref_services);
NXSetServicesMenuItemEnabled("Compiler/Show Error", pref_services);
return(self);
}
//
// Services activated functions
//
- doMake:(id)pasteboard userData:(const char *)user error:(char **)error
{
char *data, *ptr;
int len;
const NXAtom *types;
types=[pasteboard types];
while (types)
if (*types==NXFilenamePboardType) break;
if (!*types)
DISPLAY_ERROR("Wrong pasteboard type");
if ([pasteboard readType:NXFilenamePboardType data:(void*)&data
length:&len]) {
if (pref_pref_dir)
Get_Default_By_Name("Compiler", "directory", CompilerDefaults);
else {
ptr=data+strlen(data);
while (*ptr!='/') ptr--;
set_file(ptr+1);
*ptr=0;
if (strcmp(data, directory)) {
set_directory(data);
prompt_User=TRUE;
}
}
vm_deallocate(task_self(), (vm_address_t)data, len);
}
[self doMake:self];
return(self);
}
- nextError:(id)pasteboard userData:(const char *)user error:(char **)error
{
[self nextError:self];
return(self);
}
//
// Delegate methods for the subprocess object
//
- subprocessOutput:(char *)text
{
int cnt;
NXSelPt start, end;
cnt=strlen(text);
if (cnt) {
[[textfield docView] setAutodisplay:FALSE];
[[textfield docView] getSel:&start :&end];
[[textfield docView] setSel:end_pos :end_pos];
[[textfield docView] replaceSel:text];
[[textfield docView] setSel:start.cp :end.cp];
[[textfield docView] display];
[[textfield docView] setAutodisplay:TRUE];
end_pos+=cnt;
}
return(self);
}
- subprocessDone:(int)status
{
NXStream *data;
char buf[10], c;
BOOL result=TRUE, more;
int pos;
[process free];
process=0;
data=[[textfield docView] stream];
NXSeek(data, 0, NX_FROMEND);
Find_Newline(data, 0);
do {
pos=NXTell(data)-2;
NXRead(data, buf, 9);
buf[9]=0;
if (!strcmp(buf, "*** Exit ")) {
do {
c=NXGetc(data);
} while ((c>='0') && (c<='9'));
if (c=='\n') {
result=FALSE;
break;
}
}
NXSeek(data, pos, NX_FROMSTART);
more=Find_Newline(data, 0);
} while (more);
if (result && !status) {
[[textfield window] setTitle:"Compile Done -- SUCCESS"];
if (good_cmd && *good_cmd) system(good_cmd);
if (hide_on_success) [NXApp hide:self];
} else {
[[textfield window] setTitle:"Compile Done -- FAILURE"];
if (bad_cmd && *bad_cmd) system(bad_cmd);
}
Make_In_Progress=FALSE;
return(self);
}
- subprocessError:(char *)msg
{
DISPLAY_ERROR(msg);
return(self);
}
//
// User interface activated functions
//
-doMake:(id)sender
{
char *shell, *ptr;
if (Make_In_Progress) {
NXRunAlertPanel("Busy", "Compilation in progress. Please start your compilation when the current one finishes", "OK", 0, 0);
return(self);
}
if (prompt_User) {
[[cmd_form window] makeKeyAndOrderFront:self];
[cmd_form setStringValue:directory at:0];
[cmd_form setStringValue:command at:1];
return(self);
}
Make_In_Progress=TRUE;
[[textfield window] makeKeyAndOrderFront:self];
[[textfield docView] setSel:0 :0];
shell=getenv("SHELL");
if (!shell) shell="/bin/csh";
process=[[Subprocess alloc] init:shell withDelegate:self
andPtySupport:FALSE andStdErr:TRUE];
if (!process) {
DISPLAY_ERROR("Failed to create child process");
Make_In_Progress=FALSE;
return(self);
}
if (file) {
[process send:"set file=" withNewline:FALSE];
[process send:file withNewline:TRUE];
ptr=file+strlen(file);
while (--ptr>=file)
if (*ptr=='.') {
*ptr=0;
break;
}
[process send:"set stripped=" withNewline:FALSE];
[process send:file withNewline:TRUE];
if (ptr>=file) *ptr='.';
}
if (directory) {
[process send:"set dir=" withNewline:FALSE];
[process send:directory withNewline:TRUE];
}
[process send:"echo cd " withNewline:FALSE];
[process send:directory withNewline:TRUE];
[process send:"cd " withNewline:FALSE];
[process send:directory withNewline:TRUE];
[process send:"echo " withNewline:FALSE];
[process send:command withNewline:TRUE];
[process send:"exec " withNewline:FALSE];
[process send:command withNewline:TRUE];
[process terminateInput];
[[textfield window] setTitle:"Compile¼Running"];
end_pos=0;
[[textfield docView] setText:""];
[[textfield docView] setSel:0 :0];
return(self);
}
- nextError:(id)sender
{
NXSelPt start, end;
NXStream *data;
char *file, *path;
int line;
[[textfield docView] getSel:&start :&end];
data=[[textfield docView] stream];
if (start.cp<0) start.cp=0;
NXSeek(data, end.cp, NX_FROMSTART);
Find_Newline(data, 0);
while (!NXAtEOS(data)) {
start.cp=NXTell(data);
if (parse_error(data, &file, &line)) {
Find_Newline(data, 1);
end.cp=NXTell(data);
[[textfield docView] setSel:start.cp :end.cp];
[[textfield docView] scrollSelToVisible];
path=malloc(strlen(directory)+strlen(file)+2);
sprintf(path, "%s/%s", directory, file);
[self positionOnFile:path Line:line];
free(path);
free(file);
break;
}
}
return(self);
}
- stopMake:(id)sender
{
if (Make_In_Progress) {
[process terminate:self];
[self subprocessOutput:"TERMINATED\n"];
}
return(self);
}
- resetPrefs:sender
{
char *hold_directory, *hold_command;
hold_directory=directory;
hold_command=command;
directory=0;
command=0;
Reset_Defaults(CompilerDefaults);
[self show_prefs:self];
set_directory(hold_directory);
command=hold_command;
return(self);
}
- setPrefs:sender
{
set_directory((char *)[pref_form stringValueAt:0]);
command=(char *)[pref_form stringValueAt:1];
good_cmd=(char *)[pref_form stringValueAt:2];
bad_cmd=(char *)[pref_form stringValueAt:3];
pref_services=[service_switch intValue];
pref_pref_dir=[pref_dir_switch intValue];
hide_on_success=[hide_switch intValue];
Put_Full_Defaults("Compiler", CompilerDefaults);
NXSetServicesMenuItemEnabled("Compiler/Make", pref_services);
NXSetServicesMenuItemEnabled("Compiler/Show Error", pref_services);
prompt_User=FALSE;
[[pref_form window] orderOut:self];
return(self);
}
- setValues:sender
{
prompt_User=FALSE;
set_directory((char *)[cmd_form stringValueAt:0]);
command=(char *)[cmd_form stringValueAt:1];
[[cmd_form window] orderOut:self];
[self doMake:self];
return(self);
}
- show_help:sender
{
[self loadAux];
[NXGetNamedObject("Help", self) makeKeyAndOrderFront:self];
return(self);
}
- show_info:sender
{
[self loadAux];
[NXGetNamedObject("Info", self) makeKeyAndOrderFront:self];
return(self);
}
- show_license:sender
{
[self loadAux];
[NXGetNamedObject("License", self) makeKeyAndOrderFront:self];
return(self);
}
- show_prefs:sender
{
[self loadAux];
[pref_form setStringValue:directory at:0];
[pref_form setStringValue:command at:1];
[pref_form setStringValue:good_cmd at:2];
[pref_form setStringValue:bad_cmd at:3];
[service_switch setIntValue:pref_services];
[pref_dir_switch setIntValue:pref_pref_dir];
[hide_switch setIntValue:hide_on_success];
[NXGetNamedObject("Preferences", self) makeKeyAndOrderFront:self];
return(self);
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.