├── src ├── viewer.h ├── element.h ├── shell.h ├── Makefile ├── parcp-usb.h ├── ceh.c ├── parcperr.h ├── cfgopts.h ├── box.h ├── crc32.c ├── global.h ├── menu.h ├── Makefile.demo ├── parstruc.h ├── parcommo.c ├── par_io.c ├── global.c ├── Makefile.mingw ├── parinout.c ├── Makefile.dos ├── Makefile.linux ├── Makefile.osx ├── match.h ├── Makefile.mint ├── sort.c ├── parcp68k.asm ├── parcplow.h ├── parcplow.c ├── parcpcfg.c ├── parcp.h ├── parcp-usb.c ├── viewer.c ├── menu.c ├── box.c ├── partest.c ├── cfgopts.c ├── match.c └── parftpcl.c ├── .gitignore ├── README.md └── doc ├── COMPILING.txt ├── quick.txt └── cesky.txt /src/viewer.h: -------------------------------------------------------------------------------- 1 | void viewer(char *fname); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.o 2 | src/parcp 3 | src/parcpkey 4 | src/parcp*.cfg 5 | src/auto.txt 6 | src/parcp.log 7 | dosbox 8 | osx 9 | release 10 | reg 11 | -------------------------------------------------------------------------------- /src/element.h: -------------------------------------------------------------------------------- 1 | #ifndef _element_h 2 | #define _element_h 3 | 4 | typedef unsigned char BYTE; 5 | typedef unsigned short UWORD; 6 | typedef enum {FALSE,TRUE} MYBOOL; 7 | 8 | #endif /* _element_h */ 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PARCP (PARallel CoPy) 2 | Software for transferring files between Atari, Apple, PC and other computers over parallel (printer) ports, and USB (with [PARCP-USB interface](https://joy.sophics.cz/parcp/parcp-usb.html)). 3 | 4 | https://joy.sophics.cz/parcp/ 5 | -------------------------------------------------------------------------------- /src/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef _shell_h 2 | #define _shell_h 3 | 4 | #include "element.h" /* specially for MYBOOL */ 5 | 6 | /* whole Parshell is displayed in sirka x vyska screen array */ 7 | extern int sirka, vyska; 8 | extern int original_cursor; /* original cursor state */ 9 | extern MYBOOL has_dim; 10 | 11 | #endif /* _shell_h */ 12 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | FILE=Makefile.mingw 3 | else 4 | ifneq ($(DJGPP),) 5 | FILE=Makefile.dos 6 | else 7 | OS=$(shell uname) 8 | 9 | ifeq ($(OS), MiNT) 10 | FILE=Makefile.mint 11 | endif 12 | 13 | ifeq ($(OS), Linux) 14 | FILE=Makefile.linux 15 | endif 16 | endif 17 | endif 18 | ifeq ($(FILE), ) 19 | $(error Your platform ${OS} is not supported at this time.) 20 | endif 21 | 22 | include $(FILE) 23 | -------------------------------------------------------------------------------- /src/parcp-usb.h: -------------------------------------------------------------------------------- 1 | #include "element.h" 2 | #define USB_BLOCK_SIZE 60 3 | int usb_init(const char *serial); 4 | void usb_exit(); 5 | MYBOOL set_mode(unsigned char output); 6 | MYBOOL set_strobe(unsigned char strobe); 7 | MYBOOL parcpusb_command(unsigned char command); 8 | int get_busy(); 9 | int usb_set_client_read_size(long n); 10 | int usb_set_server_read_size(long n); 11 | int usb_set_client_write_size(long n, const BYTE *); 12 | int usb_set_server_write_size(long n, const BYTE *); 13 | int usb_read_block(BYTE *block, long offset, int n); 14 | int usb_write_block(const BYTE *block, long offset, int n); 15 | -------------------------------------------------------------------------------- /src/ceh.c: -------------------------------------------------------------------------------- 1 | /* Support for GEMDOS extended vectors */ 2 | 3 | static void *old_term, *old_critic; 4 | typedef void (* void_fun_pointer)(void); 5 | 6 | static void new_term(void) 7 | { 8 | void (*terminate)(void) = old_term; 9 | 10 | (void)Setexc(0x101, (void_fun_pointer)old_critic); 11 | (void)Setexc(0x102, (void_fun_pointer)old_term); 12 | terminate (); 13 | } 14 | 15 | static long /*cdecl*/ new_critic(int code) 16 | { 17 | return code; 18 | } 19 | 20 | void DODisableCEH(void) 21 | { 22 | if (getenv ("LEAVE_CEH_ALONE")) return; 23 | 24 | old_term = Setexc (0x0102, new_term); 25 | old_critic = Setexc (0x0101, (void_fun_pointer)new_critic); 26 | } 27 | -------------------------------------------------------------------------------- /src/parcperr.h: -------------------------------------------------------------------------------- 1 | #ifndef _parcperr_h 2 | #define _parcperr_h 3 | 4 | /* list of PARCP result codes */ 5 | 6 | #define NO_ERROR 0 7 | /* errors during file transfer */ 8 | #define INTERRUPT_TRANSFER 1 9 | #define QUIT_TRANSFER 2 10 | #define FILE_NOTFOUND 3 11 | #define FILE_SKIPPED 4 12 | #define ERROR_CRC_FAILED 5 13 | #define ERROR_READING_FILE 6 14 | #define ERROR_WRITING_FILE 7 15 | #define ERROR_DELETING_FILE 8 16 | #define ERROR_CREATING_DIRECTORY 9 17 | /* fatal errors - PARCP exited */ 18 | #define ERROR_USERSTOP 100 19 | #define ERROR_TIMEOUT 101 20 | #define ERROR_BADDATA 102 21 | #define ERROR_BUGPRG 103 22 | #define ERROR_MEMORY 104 23 | #define ERROR_HANDSHAKE 105 24 | #define ERROR_BADCFG 106 25 | #define ERROR_NOTROOT 107 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/cfgopts.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** CFGOPTS.H 3 | */ 4 | 5 | #ifndef TAG_TYPE_defined 6 | #define TAG_TYPE_defined 7 | typedef enum { 8 | Error_Tag, 9 | Byte_Tag, 10 | Boolean_Tag, 11 | Word_Tag, 12 | Int_Tag, 13 | Long_Tag, 14 | HexWord_Tag, 15 | HexInt_Tag, 16 | HexLong_Tag, 17 | Float_Tag, 18 | Double_Tag, 19 | Char_Tag, 20 | String_Tag, 21 | Function_Tag 22 | } TAG_TYPE; 23 | 24 | struct Config_Tag { 25 | char *code; /* Option switch */ 26 | TAG_TYPE type; /* Type of option */ 27 | void *buf; /* Storage location */ 28 | short buf_size; /* Storage size for String_Tag - max. 32k */ 29 | char stat; /* internal flag for update_config */ 30 | }; 31 | 32 | int input_config(const char *, struct Config_Tag *, char *); 33 | int update_config(const char *, struct Config_Tag *, char *); 34 | #endif 35 | -------------------------------------------------------------------------------- /src/box.h: -------------------------------------------------------------------------------- 1 | #ifndef _box_h 2 | #define _box_h 3 | 4 | #include "cfgopts.h" /* for EditNumber */ 5 | 6 | #define myIDOK 1 7 | #define myIDCANCEL 2 8 | #define myIDYES 3 9 | #define myIDNO 4 10 | #define myIDRETRY 5 11 | #define myIDABORT 6 12 | #define myIDIGNORE 7 13 | 14 | #define myMB_OK 1 15 | #define myMB_OKCANCEL 2 16 | #define myMB_YESNO 3 17 | #define myMB_YESNOCANCEL 4 18 | #define myMB_RETRYCANCEL 5 19 | #define myMB_ABORTRETRYIGNORE 6 20 | #define myMB_DEFBUTTON1 0x00 21 | #define myMB_DEFBUTTON2 0x10 22 | #define myMB_DEFBUTTON3 0x20 23 | 24 | int myMessageBox(const char *text, int type); 25 | void InfoBox(const char *text, int timeout, MYBOOL button); 26 | MYBOOL EditBox(const char *title, const char *text, char *return_str, int maxlen); 27 | int EditNumber(const char *title, const char *text, TAG_TYPE tag, void *storage); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /doc/COMPILING.txt: -------------------------------------------------------------------------------- 1 | How to compile PARCP for various platforms: 2 | =========================================== 3 | 4 | 1) on MiNT (requires patched MiNTlib and ncurses): 5 | $ make clean tgz 6 | 7 | 2) on Linux (requires libncurses, libusb and libhidapi): 8 | $ sudo apt install libncurses-dev libusb-1.0-0-dev libhidapi-dev 9 | $ make clean tgz 10 | 11 | 3) for DOS on Linux (requires dosbox, DJGPP and PDCurses): 12 | $ dosbox 13 | > set PATH=C:\DJGPP\BIN;%PATH% 14 | > set DJGPP=C:\DJGPP\DJGPP.ENV 15 | > make clean all 16 | 17 | 4) on Windows (requires MingGW, PDCurses and HIDAPI) 18 | Alt+F2 cmd.exe 19 | > set PATH=C:\Qt\Tools\mingw48_32\bin;%PATH% 20 | > cd \parcp\src 21 | > copy \pdcurses\curses.h 22 | > mingw32-make clean all 23 | 24 | 5) for Mac OS X on Linux (requires i686 gcc cross compiler) 25 | $ make -f Makefile.osx clean tgz 26 | 27 | -------------------------------------------------------------------------------- /src/crc32.c: -------------------------------------------------------------------------------- 1 | #define TABLE_SIZE 256 2 | 3 | static unsigned long crc32tab[TABLE_SIZE]; 4 | 5 | void init_CRC32(void) 6 | { 7 | int i, inx; 8 | int carry32; 9 | unsigned long entry32; 10 | 11 | for (inx = 0; inx < TABLE_SIZE; ++inx) { 12 | entry32 = inx; 13 | 14 | for (i = 0; i < 8; ++i) { 15 | carry32 = entry32 & 1; 16 | entry32 >>= 1; 17 | if (carry32) 18 | entry32 ^= 0xedb88320; 19 | } 20 | 21 | crc32tab[inx] = entry32; 22 | } 23 | } 24 | 25 | unsigned long compute_CRC32(const unsigned char *buf, int count) 26 | { 27 | int i; 28 | unsigned char inx32; 29 | unsigned long crc32; 30 | 31 | crc32 = 0xffffffff; /* pre-condition - bits all ones */ 32 | 33 | for (i = 0; i < count; ++i) { 34 | inx32 = buf[i] ^ crc32; 35 | crc32 >>= 8; 36 | crc32 ^= crc32tab[inx32]; 37 | } 38 | crc32 ^= 0xffffffff; /* post-condition - one's complement */ 39 | 40 | return crc32; 41 | } 42 | -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | /* Extern definitions of global variables for PARCP */ 2 | 3 | extern char cfg_fname[MAXPATH]; 4 | 5 | extern char local_machine[MAXSTRING]; 6 | extern char remote_machine[MAXSTRING]; 7 | 8 | extern MYBOOL hash_mark; 9 | extern MYBOOL _case_sensitive; 10 | extern MYBOOL _preserve_case; 11 | extern MYBOOL _show_hidden; 12 | extern char _over_older; 13 | extern char _over_newer; 14 | extern MYBOOL _send_subdir; 15 | extern MYBOOL _keep_timestamp; 16 | extern MYBOOL _keep_attribs; 17 | extern MYBOOL _archive_mode; 18 | extern MYBOOL _check_info; 19 | extern MYBOOL _assembler; 20 | extern MYBOOL afterdrop; 21 | extern MYBOOL _checksum; 22 | extern char _sort_jak; 23 | extern MYBOOL _sort_case; 24 | extern short dirbuf_lines; 25 | extern long buffer_lenkb; 26 | extern BYTE filebuffers; 27 | extern int time_out; 28 | extern char autoexec[MAXPATH]; 29 | #ifdef SHELL 30 | extern MYBOOL shell; 31 | #endif 32 | #ifdef USB 33 | extern char usb_serial[MAXSTRING]; 34 | #endif 35 | 36 | #ifdef DEBUG 37 | extern short debuglevel; 38 | extern char logfile[MAXSTRING]; 39 | extern char nolog_str[MAXSTRING]; 40 | extern char nodisp_str[MAXSTRING]; 41 | #endif 42 | -------------------------------------------------------------------------------- /src/menu.h: -------------------------------------------------------------------------------- 1 | #ifndef _menu_h 2 | #define _menu_h 3 | 4 | #include "element.h" 5 | #include 6 | 7 | #define MENU_PASSED (1<<0) 8 | #define MENU_SUBTREE (1<<1) 9 | #define MENU_DISABLED (1<<2) 10 | #define MENU_CHECKED (1<<3) 11 | #define MENU_CHECKABLE (1<<4) 12 | #define MENU_RADIO (1<<5) 13 | 14 | #define TITWIDTH 20 /* max. title length */ 15 | 16 | struct _tmenu { 17 | char title[TITWIDTH+1]; /* item label */ 18 | char stat_text[70]; /* item description */ 19 | BYTE flag; /* mask */ 20 | int command; /* action */ 21 | int parent;/* rodic */ 22 | struct _tmenu *next; /* next */ 23 | struct _tmenu *wnew; /* new */ 24 | }; 25 | 26 | typedef struct _tmenu TMENU; 27 | 28 | TMENU *new_item(const char *title, const char *stat_text, int command, int parent); 29 | TMENU *new_menu(TMENU **itemlist); 30 | void free_item(TMENU *item); 31 | void show_items(WINDOW *win, TMENU *smenu, int poloha); 32 | void toggle_command(TMENU *first, int cm, int set); 33 | void toggle_icheck(TMENU *first, int cm, int set); 34 | void click_radio(TMENU *first, int cm); 35 | MYBOOL is_checked(TMENU *first, int cm); 36 | int show_menu(TMENU *imenu, int cx, int cy); 37 | 38 | #endif /* _menu_h */ 39 | -------------------------------------------------------------------------------- /doc/quick.txt: -------------------------------------------------------------------------------- 1 | PARCP Quick start guide: 2 | ======================== 3 | 4 | You've got two computers. One will be PARCP Client (usually the one you 5 | want to work on) and the other one will be PARCP Server (you don't need 6 | its monitor nor keyboard as it will work unattended). 7 | 8 | A) Atari users (TOS/MiNT/MagiC): 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | 1) start PAR_IN.PRG (not required when using PARCP-USB adapter) 11 | 2) connect PARCP cable or the PARCP-USB adapter to parallel port 12 | 3) start PARCP.TTP (or PARSERVE.TOS if Atari is to be the Server) 13 | 14 | B) Apple or PC users (DOS/Windows/Linux/Raspbian): 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | 1) start PAR_IN (not required when using PARCP-USB adapter) 17 | 2) connect PARCP or USB cable (from the PARCP-USB adapter) to your PC 18 | 3) start PARCP (or PARSERVE if PC is to be the Server) 19 | 20 | This should start PARCP in its fullscreen interface for easy copying 21 | of files. But that's not the top of PARCP features! PARCP is able to copy 22 | by simple drag&drop of files onto PARCP Client icon, or even 23 | work fully automatically driven by commands in script files. 24 | 25 | Please read PARCP.HTML for more information. 26 | -------------------------------------------------------------------------------- /src/Makefile.demo: -------------------------------------------------------------------------------- 1 | # possible options: 2 | # DEBUG 3 | # Include debug support 4 | # LOWDEBUG: 5 | # Include lowlevel debug support 6 | OPTIONS = -DIBM -I../ncurses-4.1/include -DSTANDALONE 7 | 8 | CC = gcc 9 | FLAGS = -O2 -fomit-frame-pointer -Wall $(OPTIONS) -static 10 | 11 | CSRC := parcp.c parcplow.c parcommo.c match.c cfgopts.c \ 12 | global.c par_io.c parcpcfg.c crc32.c parinout.c 13 | OBJS := parcp.o match.o cfgopts.o global.o 14 | 15 | # SHELL support in PARCP? 16 | USE_SHELL = yes 17 | 18 | ifdef USE_SHELL 19 | CSRC += shell.c menu.c viewer.c box.c 20 | OBJS += shell.o 21 | FLAGS += -DSHELL 22 | endif 23 | 24 | ####################################################### 25 | 26 | parcp: $(OBJS) 27 | $(CC) $(FLAGS) -o $@ $(OBJS) -lpanel -lncurses -L../ncurses-4.1/lib -s 28 | strip $@ 29 | 30 | par_in: par_in.o 31 | $(CC) $(FLAGS) -o $@ par_in.o cfgopts.o global.o -s 32 | strip $@ 33 | 34 | par_out: par_out.o 35 | $(CC) $(FLAGS) -o $@ par_out.o cfgopts.o global.o -s 36 | strip $@ 37 | 38 | $(OBJS): %.o: %.c 39 | $(CC) $(FLAGS) -c $< -o $@ 40 | 41 | par_in.o: parinout.c 42 | $(CC) $(FLAGS) -DIN -c parinout.c -o $@ 43 | 44 | par_out.o: parinout.c 45 | $(CC) $(FLAGS) -DOUT -c parinout.c -o $@ 46 | 47 | all: parcp par_in par_out 48 | 49 | clean: 50 | rm -f *.o parcp par_in par_out 51 | 52 | tgz: parcp par_in par_out 53 | rm -f parcp.tgz 54 | tar czvf parcp.tgz parcp par_in par_out 55 | 56 | dep: 57 | $(CC) $(FLAGS) -MM $(CSRC) >.depend 58 | 59 | -include .depend 60 | -------------------------------------------------------------------------------- /src/parstruc.h: -------------------------------------------------------------------------------- 1 | struct Config_Tag mconfigs[] = { 2 | #ifdef IBM 3 | # ifdef USB 4 | { "UsbSerial", String_Tag, usb_serial, sizeof(usb_serial) }, 5 | # else 6 | { CFG_PORT, HexInt_Tag, &print_port }, 7 | { CFG_UNIBI, Boolean_Tag, &PCunidirect }, 8 | { "PortType", Int_Tag, &port_type }, 9 | { "CableType", Int_Tag, &cable_type }, 10 | # endif 11 | #endif 12 | { "FastRoutines", Boolean_Tag, &_assembler }, 13 | { "ProcessSubDir", Boolean_Tag, &_send_subdir }, 14 | { "CaseSensitive", Boolean_Tag, &_case_sensitive }, 15 | { "PreserveCase", Boolean_Tag, &_preserve_case }, 16 | { "ShowHidden", Boolean_Tag, &_show_hidden }, 17 | { "OverOlder", Char_Tag, &_over_older }, 18 | { "OverNewer", Char_Tag, &_over_newer }, 19 | { "KeepTimeStamp", Boolean_Tag, &_keep_timestamp }, 20 | { "KeepAttribs", Boolean_Tag, &_keep_attribs }, 21 | { "HashMark", Boolean_Tag, &hash_mark }, 22 | { "QuitAfterDrop", Boolean_Tag, &afterdrop }, 23 | { "CRC", Boolean_Tag, &_checksum }, 24 | { "BlockSize", Long_Tag, &buffer_lenkb }, 25 | { "DirectoryLines", Word_Tag, &dirbuf_lines }, 26 | { "FileBuffers", Byte_Tag, &filebuffers }, 27 | { "Timeout", Int_Tag, &time_out }, 28 | { "DirSort", Char_Tag, &_sort_jak }, 29 | { "SortCase", Boolean_Tag, &_sort_case }, 30 | { "Autoexec", String_Tag, autoexec, sizeof(autoexec) }, 31 | { "ArchiveMode", Boolean_Tag, &_archive_mode }, 32 | { "CollectInfo", Boolean_Tag, &_check_info }, 33 | 34 | #ifdef SHELL 35 | { "Shell", Boolean_Tag, &shell }, 36 | #endif 37 | 38 | #ifdef DEBUG 39 | { "Debug", Word_Tag, &debuglevel }, 40 | { "LogFile", String_Tag, logfile, sizeof(logfile) }, 41 | { "NoLog", String_Tag, nolog_str, sizeof(nolog_str) }, 42 | { "NoDisplay", String_Tag, nodisp_str, sizeof(nodisp_str) }, 43 | #endif 44 | { NULL , Error_Tag, NULL } 45 | }; 46 | -------------------------------------------------------------------------------- /src/parcommo.c: -------------------------------------------------------------------------------- 1 | /* common functions for PARCP, PARINOUT and PARTEST */ 2 | 3 | MYBOOL file_existuje(char *fname) 4 | { 5 | FILE *f = fopen(fname, "r"); 6 | if (f != NULL) { 7 | fclose(f); 8 | return TRUE; 9 | } 10 | else 11 | return FALSE; 12 | } 13 | 14 | MYBOOL hledej_config(char *argv[], char *cesta) 15 | { 16 | char *p; 17 | MYBOOL konfigOK = FALSE; 18 | 19 | if ((p = getenv(PARCPDIR)) != NULL) { 20 | strcpy(cesta, p); /* by environment variable */ 21 | 22 | p = cesta + strlen(cesta)-1; 23 | if (*p != SLASH && *p != BACKSLASH) 24 | strcat(cesta, SLASH_STR); 25 | strcat(cesta, CFGFILE); 26 | konfigOK = file_existuje(cesta); 27 | if (! konfigOK) { 28 | printf(PARCPDIR" is set but '%s' is not found!\n\n", cesta); 29 | sleep(2); 30 | } 31 | } 32 | 33 | if (! konfigOK && argv[0] != NULL) { 34 | strcpy(cesta, argv[0]); /* in PARCP home folder */ 35 | /* strip program name but retain folder delimiter */ 36 | p = strrchr(cesta, SLASH); 37 | if (p == NULL) 38 | p = strrchr(cesta, BACKSLASH); 39 | /* if there isn't folder delimiter it was not a file path thus it's unusable */ 40 | if (p != NULL) { 41 | *(p+1) = 0; 42 | strcat(cesta, CFGFILE); 43 | konfigOK = file_existuje(cesta); 44 | } 45 | } 46 | 47 | if (! konfigOK) { 48 | char *ret = getcwd(cesta, MAXPATH); /* in current folder */ 49 | ret = ret; // UNUSED 50 | p = cesta + strlen(cesta)-1; 51 | if (*p != SLASH && *p != BACKSLASH) 52 | strcat(cesta, SLASH_STR); 53 | strcat(cesta, CFGFILE); 54 | konfigOK = file_existuje(cesta); 55 | } 56 | 57 | #ifdef _WIN32 58 | # define DOMA "HOMEDATA" 59 | #else 60 | # define DOMA "HOME" 61 | #endif 62 | 63 | if (! konfigOK && (p = getenv(DOMA)) != NULL) { 64 | strcpy(cesta, p); /* by environment variable */ 65 | 66 | p = cesta + strlen(cesta)-1; 67 | if (*p != SLASH && *p != BACKSLASH) 68 | strcat(cesta, SLASH_STR); 69 | strcat(cesta, CFGFILE); 70 | konfigOK = file_existuje(cesta); 71 | } 72 | 73 | return konfigOK; 74 | } 75 | -------------------------------------------------------------------------------- /src/par_io.c: -------------------------------------------------------------------------------- 1 | #include "parcp.h" 2 | #include "parcplow.h" 3 | 4 | #ifdef IBM 5 | #include "global.h" 6 | #include "parstruc.h" 7 | #include "parcommo.c" 8 | 9 | void zpracovani_parametru(int argc, char *argv[]) 10 | { 11 | char cesta[MAXPATH]; 12 | extern char *optarg; 13 | MYBOOL konfigOK = FALSE; 14 | 15 | /* first read the config file */ 16 | konfigOK = hledej_config(argv, cesta); 17 | 18 | /* check if there isn't config file name on the comand line */ 19 | if (argc == 2 && argv[1] != NULL) { 20 | strcpy(cesta, argv[1]); 21 | konfigOK = file_existuje(cesta); 22 | } 23 | 24 | if (konfigOK) { 25 | printf("Configuration file used: %s\n", cesta); 26 | print_port = port_type = -1; 27 | if (input_config(cesta,configs,CFGHEAD) <= 0) { 28 | printf("Error while reading/processing the config file.\n\n"); 29 | exit(-1); 30 | } 31 | if (print_port == -1 || port_type == -1) { 32 | puts("Invalid PARCP configuration file. Please run PARTEST for updating it."); 33 | exit(-1); 34 | } 35 | } 36 | else { 37 | printf("Fatal error - can't find PARCP config file.\n"); 38 | exit(-1); 39 | } 40 | printf("Parallel port base address: $%x\n", print_port); 41 | printf("Parallel port type: %s\n", port_type == 0 ? "unidirectional" : "bidirectional"); 42 | if (PCunidirect) 43 | printf("Using UNI-BI HW parallel adapter\n"); 44 | } 45 | #endif /* IBM */ 46 | 47 | void main(int argc, char *argv[]) 48 | { 49 | #ifdef IBM 50 | 51 | zpracovani_parametru(argc, argv); 52 | 53 | /* in Linux get the permission to access hardware of the parallel port directly */ 54 | #ifndef __MSDOS__ 55 | ioperm(print_port,4,1); 56 | #endif 57 | 58 | if (port_type == 2 && !PCunidirect) 59 | ECP2EPP; 60 | #endif /* IBM */ 61 | 62 | SET_INPUT; 63 | 64 | while(KEYPRESSED != 8) { 65 | BYTE x; 66 | 67 | putchar(' '); 68 | putchar(IS_READY ? '^' : 'v'); 69 | GET_BYTE(x); 70 | printf("%02x", x); 71 | switch(KEYPRESSED) { 72 | case 4: 73 | STROBE_HIGH; 74 | break; 75 | case 2: 76 | STROBE_LOW; 77 | break; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/global.c: -------------------------------------------------------------------------------- 1 | /* Global variables for PARCP */ 2 | #include "parcp.h" 3 | 4 | char cfg_fname[MAXPATH]; /* file path to actual config file */ 5 | 6 | char local_machine[MAXSTRING]; 7 | char remote_machine[MAXSTRING]; 8 | 9 | MYBOOL hash_mark = TRUE; 10 | MYBOOL _case_sensitive = TRUE; /* in the match() consider upper/lower case */ 11 | MYBOOL _preserve_case = TRUE; /* in the opendir() do not convert DOS filenames to lower case */ 12 | MYBOOL _show_hidden = FALSE; /* show hidden files */ 13 | char _over_older = 'R'; /* overwrite older files without prompt [Replace]*/ 14 | char _over_newer = 'A'; /* overwrite newer files with prompt [Ask]*/ 15 | MYBOOL _send_subdir = TRUE; /* send files in folders recursively */ 16 | MYBOOL _keep_timestamp = TRUE; /* restore original timestamp on copied files */ 17 | MYBOOL _keep_attribs = FALSE; /* restore original attributes on copied files */ 18 | MYBOOL _archive_mode = FALSE; /* DOS-like fs: copy just files with ARCHIVE attribute unset and update the attribute on the original file after succesful copying */ 19 | MYBOOL _check_info = FALSE; /* count files/folders before copy/delete */ 20 | MYBOOL _assembler = TRUE; /* use fast transfer routines */ 21 | MYBOOL afterdrop = TRUE; /* server quits after drag&drop */ 22 | MYBOOL _checksum = FALSE; /* use CRC for better safety of transferred data blocks */ 23 | char _sort_jak = 'N'; /* how to sort files [by Name] */ 24 | MYBOOL _sort_case = FALSE; /* sort upper/lower case differently */ 25 | UWORD dirbuf_lines = DIRBUF_LIN; /* reserved number of lines of 'DIRLINELEN' length */ 26 | long buffer_lenkb = BUFFER_LENKB; /* the size of transferred block in kilobytes */ 27 | BYTE filebuffers = 1; /* the number of blocks reserved for buffered file I/O */ 28 | int time_out = TIME_OUT; /* timeout in seconds */ 29 | char autoexec[MAXPATH]=""; 30 | #ifdef SHELL 31 | MYBOOL shell = TRUE; 32 | #endif 33 | #ifdef USB 34 | char usb_serial[MAXSTRING] = ""; 35 | #endif 36 | 37 | #ifdef DEBUG 38 | short debuglevel=1; 39 | char logfile[MAXSTRING]="parcp.log"; 40 | char nolog_str[MAXSTRING]="l"; 41 | char nodisp_str[MAXSTRING]="ldsr>!"; 42 | #endif 43 | -------------------------------------------------------------------------------- /src/Makefile.mingw: -------------------------------------------------------------------------------- 1 | DEBUG = 2 | #DEBUG = -DUSBDEBUG 3 | #DEBUG = -DIODEBUG 4 | #DEBUG = -DDEBUG 5 | #DEBUG = -DDEBUG -DLOWDEBUG 6 | #DEBUG = -DDEBUG -DLOWDEBUG -DIODEBUG 7 | 8 | HAVE_USB = -DUSB -I/Qt 9 | 10 | LIB_USB = -L/Qt/HIDAPI/windows -lHIDAPI -lsetupapi 11 | 12 | STATIC = 13 | #STATIC = -static 14 | #LDSTATIC = -ltinfo -lpthread -lusb-1.0 -lrt 15 | 16 | FLAGS = $(EXT_FLAGS) -O2 -DIBM $(DEBUG) $(HAVE_USB) -I..\pdcurses -Wall -fomit-frame-pointer -fno-strength-reduce 17 | 18 | PARCLIENT = parcp.c parcp.h cfgopts.h parcplow.h parcplow.c crc32.c parcommo.c parftpcl.c sort.c 19 | 20 | ZAKL_OBJS = match.o cfgopts.o global.o parcp-usb.o 21 | 22 | OBJS = parcp.o $(ZAKL_OBJS) 23 | SEROBJS = server_parcp.o $(ZAKL_OBJS) 24 | 25 | SHELL_FLAGS = -DSHELL $(FLAGS) 26 | SHELL_OBJS = shell_parcp.o shell.o box.o menu.o viewer.o $(ZAKL_OBJS) 27 | 28 | parshell : $(SHELL_OBJS) 29 | gcc $(STATIC) $(SHELL_FLAGS) -o parcp.exe $(SHELL_OBJS) -L..\pdcurses -lpdcurses $(LIB_USB) $(LDSTATIC) 30 | strip parcp.exe 31 | 32 | parcp : $(OBJS) 33 | gcc $(STATIC) $(FLAGS) -o parcp.exe $(OBJS) $(LIB_USB) 34 | strip parcp.exe 35 | 36 | pt : parcp-usb.o 37 | gcc $(STATIC) $(FLAGS) -o pt.exe parcp-usb.o $(LIB_USB) 38 | 39 | parserve : $(SEROBJS) 40 | gcc $(STATIC) $(FLAGS) -o parserve.exe $(SEROBJS) $(LIB_USB) 41 | strip parserve.exe 42 | 43 | all : parshell parserve 44 | 45 | clean : 46 | del *.o 47 | del parcp.exe parserve.exe 48 | 49 | ############################### 50 | 51 | parcp.o : $(PARCLIENT) 52 | gcc $(FLAGS) -c parcp.c 53 | 54 | shell_parcp.o : $(PARCLIENT) 55 | gcc $(SHELL_FLAGS) -c parcp.c -o shell_parcp.o 56 | 57 | server_parcp.o : $(PARCLIENT) 58 | gcc -DPARCP_SERVER $(FLAGS) -c parcp.c -o server_parcp.o 59 | 60 | shell.o : shell.c shell.h 61 | gcc $(SHELL_FLAGS) -c shell.c 62 | 63 | box.o : box.c box.h 64 | gcc $(SHELL_FLAGS) -c box.c 65 | 66 | menu.o : menu.c menu.h 67 | gcc $(SHELL_FLAGS) -c menu.c 68 | 69 | viewer.o : viewer.c viewer.h 70 | gcc $(SHELL_FLAGS) -c viewer.c 71 | 72 | global.o : global.c global.h 73 | gcc $(SHELL_FLAGS) -c global.c 74 | 75 | match.o : match.c match.h 76 | gcc $(FLAGS) -c match.c 77 | 78 | parcp-usb.o : parcp-usb.c parcp-usb.h 79 | gcc $(FLAGS) -c parcp-usb.c 80 | 81 | cfgopts.o : cfgopts.c cfgopts.h 82 | gcc $(FLAGS) -c cfgopts.c 83 | 84 | -------------------------------------------------------------------------------- /src/parinout.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PARCP IN/OUT - written for setting the direction of parallel port. 3 | * 4 | * Petr Stehlik (c) 1996,1997 5 | * 6 | * You need a special HW interface if your PC offers unidirectional parallel 7 | * port only. 8 | */ 9 | 10 | #include "parcp.h" 11 | #include "parcplow.h" 12 | 13 | #ifdef IBM 14 | #include "global.h" 15 | #include "parstruc.h" 16 | int io_config_file(char *soubor) 17 | { 18 | return input_config(soubor, mconfigs, CFGHEAD); 19 | } 20 | 21 | #include "parcommo.c" 22 | 23 | void zpracovani_parametru(int argc, char *argv[]) 24 | { 25 | char cesta[MAXPATH]; 26 | extern char *optarg; 27 | MYBOOL konfigOK = FALSE; 28 | 29 | /* find the config file */ 30 | konfigOK = hledej_config(argv, cesta); 31 | 32 | /* check if there isn't config file path on the command line */ 33 | if (argc == 2 && argv[1] != NULL) { 34 | strcpy(cesta, argv[1]); 35 | konfigOK = file_existuje(cesta); 36 | } 37 | 38 | if (konfigOK) { 39 | printf("Configuration file used: %s\n", cesta); 40 | print_port = port_type = -1; 41 | if (input_config(cesta, mconfigs, CFGHEAD) <= 0) { 42 | printf("Error while reading/processing the config file.\n\n"); 43 | exit(-1); 44 | } 45 | if (print_port == -1 || port_type == -1) { 46 | puts("Invalid PARCP configuration file. Please run PARTEST for updating it."); 47 | exit(-1); 48 | } 49 | } 50 | else { 51 | printf("Fatal error - can't find PARCP config file.\n"); 52 | exit(-1); 53 | } 54 | printf("Parallel port base address: $%x\n", print_port); 55 | printf("Parallel port type: %s\n", port_type == 0 ? "unidirectional" : "bidirectional"); 56 | if (PCunidirect) 57 | printf("Using UNI-BI HW parallel adapter\n"); 58 | } 59 | #endif /* IBM */ 60 | 61 | int main(int argc, char *argv[]) 62 | { 63 | #ifdef IN 64 | #define TXT "IN" 65 | #else 66 | #define TXT "OUT" 67 | #endif 68 | 69 | puts("\nPARCP "TXT" - written by Petr Stehlik (c) 1996-2015.\n"\ 70 | "Version "VERZE" (compiled on "__DATE__")\n"); 71 | 72 | #ifdef IBM 73 | 74 | zpracovani_parametru(argc, argv); 75 | 76 | /* in Linux get the permission to access the hardware of parallel port directly */ 77 | #ifndef __MSDOS__ 78 | ioperm(print_port,4,1); 79 | #endif 80 | 81 | if (port_type == 2 && !PCunidirect) 82 | ECP2EPP; 83 | #endif /* IBM */ 84 | 85 | #ifdef IN 86 | SET_INPUT; 87 | printf("Parallel port is set to input (safe) state.\n"); 88 | #else 89 | SET_OUTPUT; 90 | #ifdef IBM 91 | if (port_type == 2 && !PCunidirect) 92 | EPP2ECP; 93 | #endif /* IBM */ 94 | printf("Parallel port is set to output (standard) state.\n"); 95 | #endif 96 | STROBE_HIGH; 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /doc/cesky.txt: -------------------------------------------------------------------------------- 1 | Zdravim vas, 2 | 3 | kompletni dokumentace PARCP (dnes jiz pres 100 kB textu) je napsana v 4 | anglictine. Nemam silu tolik textu napsat jeste jednou cesky a pak navic 5 | jeste udrzovat obe verze aktualni. Nastesti se PARCP ovlada tak jednoduse, 6 | ze i kdyz anglictinou nevladnete, PARCP zvladnete. Pokud mate jakekoliv 7 | pochybnosti, ihned mi napiste elektronicky uvedene v souboru PARCP.HTML (na konci). 8 | 9 | Samotny princip cinnosti je jasny: PARCP propoji dva pocitace (je jedno 10 | jestli jsou to pececka nebo nejake Atari pocitace ci klony od obojiho) pres 11 | paralelni porty (to jsou ty, kam se obvykle pripojuje tiskarna). Pak PARCP 12 | umozni prenaset soubory z jednoho pocitace na druhy, vytvaret adresare, 13 | presouvat je a mazat. Dokonce muzete zkopirovat cely disk najednou! Diky 14 | pouzitemu paralelnimu portu je prenos dat velmi rychly (az pres 100 kB 15 | za sekundu, tedy napr. celou HD disketu za 15 sekund a cele ZIP medium za 16 | necelou ctvrthodinku). 17 | 18 | Takze: mame dva pocitace. Jeden bude server (na tom delat nebudeme, ten nam 19 | bude jen slouzit) a druhy bude klient (na tom budeme zadavat pokyny pro 20 | prenos dat). Je jedno ktery bude server a ktery klient. Dulezite je jen, ze 21 | na serveru spustime PARSERVE a rozbehne se primo server. Kdyz uz bezi 22 | server, muzeme pripojit kabel (pokud jsme to uz neudelali predtim) 23 | a spustime klienta na druhem pocitaci. 24 | 25 | Ted nasleduje velmi zjednoduseny postup jak s PARCP zacit: 26 | 27 | A) Atari uzivatele: 28 | ~~~~~~~~~~~~~~~~~~~ 29 | 1) spustit PAR_IN.PRG (neni nutne pri PARCP-USB) 30 | 2) pripojit PARCP kabel nebo PARCP-USB prevodnik do paralelniho portu 31 | 3) spustit PARCP.TTP (nebo PARSERVE.TOS, pokud to ma byt server) 32 | 33 | B) PC uzivatele: 34 | ~~~~~~~~~~~~~~~~ 35 | 1) propojit PARCP-USB s PC USB kabelem 36 | 2) spustit PARCP.EXE (nebo PARSERVE.EXE, pokud to ma byt server) 37 | 38 | To je vsechno. Meli byste se octnout v celoobrazovkovem prostredi PARCP, 39 | ktere umoznuje jednoduse kopirovat, vytvaret, prohlizet ci mazat soubory 40 | nebo cele adresare (jednoduchym mackanim kurzorovych sipek a funkcnich 41 | klaves). Ovsem to neni vsechno! PARCP umi take prenaset soubory pouhym 42 | prenesenim ikon souboru a upustenim nad PARCP ikonou ci dokonce pracovat 43 | naprosto automaticky jen podle prikazu ve scenari. 44 | 45 | Vsechny dalsi informace jsou v PARCP.HTM. Je treba si to (nechat) prelouskat. 46 | Nerucim za zadne skody, zpusobene at uz primo ci neprimo behem PARCP ci 47 | pripojovanim kabelu nebo UNI-BI rozhrani k vasim paralelnim portum. Vsechny 48 | podstatne informace jak se problemum vyhnout jsem napsal v PARCP.HTML. 49 | Zakladem je spolecna zem obou pocitacu (nejlepe napajet ze stejne zasuvky) 50 | a kabely pripojovat jen pokud jsou porty ve vstupnim stavu (po spusteni 51 | PARCP_IN nebo samotneho PARCP). 52 | 53 | V pripade nejasnosti piste na adresy: 54 | 55 | mail: petr@pstehlik.cz 56 | http://joy.sophics.cz/parcp/ 57 | -------------------------------------------------------------------------------- /src/Makefile.dos: -------------------------------------------------------------------------------- 1 | DEBUG = 2 | #DEBUG = -DDEBUG 3 | #DEBUG = -DDEBUG -DLOWDEBUG 4 | #DEBUG = -DDEBUG -DLOWDEBUG -DIODEBUG 5 | 6 | STATIC = 7 | #STATIC = -static 8 | 9 | FLAGS = $(EXT_FLAGS) -O2 -DIBM $(DEBUG) -Wall -fomit-frame-pointer -fno-strength-reduce 10 | 11 | PARCLIENT = parcp.c parcp.h cfgopts.h parcplow.h parcplow.c crc32.c parcommo.c parftpcl.c sort.c 12 | 13 | ZAKL_OBJS = match.o cfgopts.o global.o 14 | 15 | OBJS = parcp.o $(ZAKL_OBJS) 16 | SEROBJS = server_parcp.o $(ZAKL_OBJS) 17 | 18 | SHELL_FLAGS = -DSHELL $(FLAGS) 19 | SHELL_OBJS = shell_parcp.o shell.o box.o menu.o viewer.o $(ZAKL_OBJS) 20 | 21 | parshell : $(SHELL_OBJS) 22 | gcc $(STATIC) $(SHELL_FLAGS) -o parcp.exe $(SHELL_OBJS) -lpanel -lpdc~1 23 | strip parcp.exe 24 | 25 | parcp : $(OBJS) 26 | gcc $(FLAGS) -o parcp.exe $(OBJS) 27 | strip parcp.exe 28 | 29 | parserve : $(SEROBJS) 30 | gcc $(FLAGS) -o parserve.exe $(SEROBJS) 31 | strip parserve.exe 32 | 33 | par_io : par_io.c global.c cfgopts.c 34 | gcc $(FLAGS) par_io.c global.c cfgopts.c -o par_io.exe 35 | strip par_io.exe 36 | 37 | par_in : par_in.o global.o cfgopts.o 38 | gcc $(SHELL_FLAGS) par_in.o global.o cfgopts.o -o par_in.exe 39 | strip par_in.exe 40 | 41 | par_out : par_out.o global.o cfgopts.o 42 | gcc $(SHELL_FLAGS) par_out.o global.o cfgopts.o -o par_out.exe 43 | strip par_out.exe 44 | 45 | parcpcfg : parcpcfg.o cfgopts.o global.o 46 | gcc $(FLAGS) parcpcfg.o cfgopts.o global.o -o parcpcfg.exe 47 | strip parcpcfg.exe 48 | 49 | partest : partest.o $(ZAKL_OBJS) 50 | gcc $(FLAGS) -o partest.exe partest.o $(ZAKL_OBJS) 51 | strip partest.exe 52 | 53 | #all : parcp par_in par_out 54 | all : parshell parserve par_in parcpcfg 55 | 56 | clean : 57 | del *.o 58 | del parcp.exe 59 | del par_in.exe 60 | del parcpcfg.exe 61 | del parserve.exe 62 | 63 | ############################### 64 | 65 | par_in.o : parinout.c 66 | gcc $(SHELL_FLAGS) -c -DIN parinout.c -o par_in.o 67 | 68 | par_out.o : parinout.c 69 | gcc $(SHELL_FLAGS) -c -DOUT parinout.c -o par_out.o 70 | 71 | parcpcfg.o : parcpcfg.c 72 | gcc $(FLAGS) -c parcpcfg.c 73 | 74 | parcp.o : $(PARCLIENT) 75 | gcc $(FLAGS) -c parcp.c 76 | 77 | partest.o : partest.c $(PARCLIENT) 78 | gcc $(FLAGS) -c partest.c 79 | 80 | shell_parcp.o : $(PARCLIENT) 81 | gcc $(SHELL_FLAGS) -c parcp.c -o shell_parcp.o 82 | 83 | server_parcp.o : $(PARCLIENT) 84 | gcc -DPARCP_SERVER $(FLAGS) -c parcp.c -o server_parcp.o 85 | 86 | shell.o : shell.c parcp.h cfgopts.h menu.c viewer.c box.c 87 | gcc $(SHELL_FLAGS) -c shell.c 88 | 89 | box.o : box.c box.h 90 | gcc $(SHELL_FLAGS) -c box.c 91 | 92 | menu.o : menu.c menu.h 93 | gcc $(SHELL_FLAGS) -c menu.c 94 | 95 | viewer.o : viewer.c viewer.h 96 | gcc $(SHELL_FLAGS) -c viewer.c 97 | 98 | global.o : global.c global.h 99 | gcc $(SHELL_FLAGS) -c global.c 100 | 101 | match.o : match.c match.h 102 | gcc $(FLAGS) -c match.c 103 | 104 | cfgopts.o : cfgopts.c cfgopts.h 105 | gcc $(FLAGS) -c cfgopts.c 106 | 107 | -------------------------------------------------------------------------------- /src/Makefile.linux: -------------------------------------------------------------------------------- 1 | # examples of running make: 2 | # for static binaries: make -e STATIC=-static 3 | # for standalone demo: make -e EXT_FLAGS=-DSTANDALONE 4 | 5 | CC = gcc 6 | STRIP = strip 7 | 8 | DEBUG = 9 | #DEBUG = -DUSBDEBUG 10 | #DEBUG = -DIODEBUG 11 | #DEBUG = -DDEBUG 12 | #DEBUG = -DDEBUG -DLOWDEBUG 13 | #DEBUG = -DDEBUG -DLOWDEBUG -DIODEBUG 14 | 15 | HAVE_USB = -DUSB -pthread 16 | LIB_USB = -lhidapi-libusb 17 | 18 | ifeq ($(HAVE_USB),) 19 | ALL_BIN = parcp parserve par_in 20 | else 21 | ALL_BIN = parcp parserve 22 | endif 23 | 24 | #STATIC = -static 25 | 26 | ifeq ($(STATIC), -static) 27 | LDSTATIC = -ltinfo -lrt -ludev 28 | endif 29 | 30 | #EXT_FLAGS = -DSTANDALONE 31 | 32 | LIB_NCURSES=-lncurses 33 | # for UTF support in ncurses use ncursesw: 34 | #LIB_NCURSES=-lncursesw 35 | 36 | FLAGS = $(EXT_FLAGS) -O2 -DIBM $(DEBUG) $(HAVE_USB) -Wall -fomit-frame-pointer -fno-strength-reduce 37 | 38 | PARCLIENT = parcp.c parcp.h cfgopts.h parcplow.h parcplow.c crc32.c parcommo.c parftpcl.c sort.c 39 | 40 | ZAKL_OBJS = match.o cfgopts.o global.o parcp-usb.o 41 | 42 | OBJS = parcp.o $(ZAKL_OBJS) 43 | SEROBJS = server_parcp.o $(ZAKL_OBJS) 44 | 45 | SHELL_FLAGS = -DSHELL $(FLAGS) 46 | SHELL_OBJS = shell_parcp.o shell.o box.o menu.o viewer.o $(ZAKL_OBJS) 47 | 48 | parcp : $(SHELL_OBJS) 49 | $(CC) $(STATIC) $(SHELL_FLAGS) -o parcp $(SHELL_OBJS) -lpanel $(LIB_NCURSES) $(LIB_USB) $(LDSTATIC) 50 | $(STRIP) $@ 51 | 52 | parcpftp : $(OBJS) 53 | $(CC) $(STATIC) $(FLAGS) -o parcp $(OBJS) $(LIB_USB) $(LDSTATIC) 54 | $(STRIP) parcp 55 | 56 | pt : parcp-usb.o 57 | $(CC) $(STATIC) $(FLAGS) -o pt parcp-usb.o $(LIB_USB) 58 | 59 | parserve : $(SEROBJS) 60 | $(CC) $(STATIC) $(FLAGS) -o parserve $(SEROBJS) $(LIB_USB) $(LDSTATIC) 61 | $(STRIP) $@ 62 | 63 | par_io : par_io.c global.c cfgopts.c 64 | $(CC) $(FLAGS) par_io.c global.c cfgopts.c -o par_io $(LIB_USB) 65 | $(STRIP) $@ 66 | 67 | par_in.o : parinout.c 68 | $(CC) $(SHELL_FLAGS) -c -DIN parinout.c -o par_in.o 69 | 70 | par_out.o : parinout.c 71 | $(CC) $(SHELL_FLAGS) -c -DOUT parinout.c -o par_out.o 72 | 73 | par_in : par_in.o global.o cfgopts.o 74 | $(CC) $(STATIC) $(SHELL_FLAGS) par_in.o global.o cfgopts.o -o par_in 75 | $(STRIP) $@ 76 | 77 | par_out : par_out.o global.o cfgopts.o 78 | $(CC) $(SHELL_FLAGS) par_out.o global.o cfgopts.o -o par_out 79 | $(STRIP) $@ 80 | 81 | parcpcfg.o : parcpcfg.c 82 | $(CC) $(FLAGS) -c parcpcfg.c 83 | 84 | parcpcfg : parcpcfg.o cfgopts.o global.o 85 | $(CC) $(FLAGS) parcpcfg.o cfgopts.o global.o -o parcpcfg 86 | $(STRIP) $@ 87 | 88 | all : $(ALL_BIN) 89 | 90 | tgz: $(ALL_BIN) 91 | rm -f parcp.tgz 92 | tar czvf parcp.tgz $(ALL_BIN) 93 | 94 | clean : 95 | rm -f *.o $(ALL_BIN) parcp.tgz 96 | 97 | ############################### 98 | 99 | parcp.o : $(PARCLIENT) 100 | $(CC) $(FLAGS) -c parcp.c 101 | 102 | shell_parcp.o : $(PARCLIENT) 103 | $(CC) $(SHELL_FLAGS) -c parcp.c -o shell_parcp.o 104 | 105 | server_parcp.o : $(PARCLIENT) 106 | $(CC) -DPARCP_SERVER $(FLAGS) -c parcp.c -o server_parcp.o 107 | 108 | shell.o : shell.c shell.h 109 | $(CC) $(SHELL_FLAGS) -c shell.c 110 | 111 | box.o : box.c box.h 112 | $(CC) $(SHELL_FLAGS) -c box.c 113 | 114 | menu.o : menu.c menu.h 115 | $(CC) $(SHELL_FLAGS) -c menu.c 116 | 117 | viewer.o : viewer.c viewer.h 118 | $(CC) $(SHELL_FLAGS) -c viewer.c 119 | 120 | global.o : global.c global.h 121 | $(CC) $(SHELL_FLAGS) -c global.c 122 | 123 | match.o : match.c match.h 124 | $(CC) $(FLAGS) -c match.c 125 | 126 | parcp-usb.o : parcp-usb.c parcp-usb.h 127 | $(CC) $(FLAGS) -c parcp-usb.c 128 | 129 | cfgopts.o : cfgopts.c cfgopts.h 130 | $(CC) $(FLAGS) -c cfgopts.c 131 | 132 | -------------------------------------------------------------------------------- /src/Makefile.osx: -------------------------------------------------------------------------------- 1 | # examples of running make: 2 | # for static binaries: make -e STATIC=-static 3 | # for standalone demo: make -e EXT_FLAGS=-DSTANDALONE 4 | 5 | CC = i686-apple-darwin10-gcc 6 | STRIP = i686-apple-darwin10-strip 7 | CFLAGS += -arch i386 -arch x86_64 8 | DEBUG = 9 | #DEBUG = -DUSBDEBUG 10 | #DEBUG = -DIODEBUG 11 | #DEBUG = -DDEBUG 12 | #DEBUG = -DDEBUG -DLOWDEBUG 13 | #DEBUG = -DDEBUG -DLOWDEBUG -DIODEBUG 14 | 15 | HAVE_USB = -DUSB -I/home/joy/Qt -pthread 16 | LIB_USB = -L/home/joy/Qt/HIDAPI/mac -lHIDAPI -lIOKit -F/usr/lib/apple/SDKs/MacOSX10.6.sdk/System/Library/Frameworks -framework CoreFoundation 17 | 18 | ifeq ($(HAVE_USB),) 19 | ALL_BIN = parcp parserve par_in 20 | else 21 | ALL_BIN = parcp parserve 22 | endif 23 | 24 | #STATIC = -static 25 | 26 | ifeq ($(STATIC), -static) 27 | LDSTATIC = -ltinfo -lrt 28 | endif 29 | 30 | #EXT_FLAGS = -DSTANDALONE 31 | EXT_FLAGS += -I/usr/lib/apple/SDKs/MacOSX10.6.sdk/usr/include -I/usr/lib/gcc/i686-apple-darwin10/4.2.1/include -L/usr/lib/apple/SDKs/MacOSX10.6.sdk/usr/lib -L/usr/lib/apple/SDKs/MacOSX10.6.sdk/usr/lib/system 32 | EXT_FLAGS += -I/home/joy/parcp/osx/ncurses-5.9/include -L/home/joy/parcp/osx/ncurses-5.9/lib 33 | 34 | LIB_NCURSES=-lncurses 35 | # for UTF support in ncurses use ncursesw: 36 | #LIB_NCURSES=-lncursesw 37 | 38 | FLAGS = $(CFLAGS) $(EXT_FLAGS) -O2 -DIBM $(DEBUG) $(HAVE_USB) -Wall -fomit-frame-pointer -fno-strength-reduce 39 | 40 | PARCLIENT = parcp.c parcp.h cfgopts.h parcplow.h parcplow.c crc32.c parcommo.c parftpcl.c sort.c 41 | 42 | ZAKL_OBJS = match.o cfgopts.o global.o parcp-usb.o 43 | 44 | OBJS = parcp.o $(ZAKL_OBJS) 45 | SEROBJS = server_parcp.o $(ZAKL_OBJS) 46 | 47 | SHELL_FLAGS = -DSHELL $(FLAGS) 48 | SHELL_OBJS = shell_parcp.o shell.o box.o menu.o viewer.o $(ZAKL_OBJS) 49 | 50 | parcp : $(SHELL_OBJS) 51 | $(CC) $(STATIC) $(SHELL_FLAGS) -o parcp $(SHELL_OBJS) -lpanel $(LIB_NCURSES) $(LIB_USB) $(LDSTATIC) 52 | $(STRIP) $@ 53 | 54 | parcpftp : $(OBJS) 55 | $(CC) $(STATIC) $(FLAGS) -o parcp $(OBJS) $(LIB_USB) $(LDSTATIC) 56 | $(STRIP) parcp 57 | 58 | pt : parcp-usb.o 59 | $(CC) $(STATIC) $(FLAGS) -o pt parcp-usb.o $(LIB_USB) 60 | 61 | parserve : $(SEROBJS) 62 | $(CC) $(STATIC) $(FLAGS) -o parserve $(SEROBJS) $(LIB_USB) $(LDSTATIC) 63 | $(STRIP) $@ 64 | 65 | par_io : par_io.c global.c cfgopts.c 66 | $(CC) $(FLAGS) par_io.c global.c cfgopts.c -o par_io $(LIB_USB) 67 | $(STRIP) $@ 68 | 69 | par_in.o : parinout.c 70 | $(CC) $(SHELL_FLAGS) -c -DIN parinout.c -o par_in.o 71 | 72 | par_out.o : parinout.c 73 | $(CC) $(SHELL_FLAGS) -c -DOUT parinout.c -o par_out.o 74 | 75 | par_in : par_in.o global.o cfgopts.o 76 | $(CC) $(STATIC) $(SHELL_FLAGS) par_in.o global.o cfgopts.o -o par_in 77 | $(STRIP) $@ 78 | 79 | par_out : par_out.o global.o cfgopts.o 80 | $(CC) $(SHELL_FLAGS) par_out.o global.o cfgopts.o -o par_out 81 | $(STRIP) $@ 82 | 83 | parcpcfg.o : parcpcfg.c 84 | $(CC) $(FLAGS) -c parcpcfg.c 85 | 86 | parcpcfg : parcpcfg.o cfgopts.o global.o 87 | $(CC) $(FLAGS) parcpcfg.o cfgopts.o global.o -o parcpcfg 88 | $(STRIP) $@ 89 | 90 | all : $(ALL_BIN) 91 | 92 | tgz: $(ALL_BIN) 93 | rm -f parcp.tgz 94 | tar czvf parcp.tgz $(ALL_BIN) 95 | 96 | clean : 97 | rm -f *.o $(ALL_BIN) parcp.tgz 98 | 99 | ############################### 100 | 101 | parcp.o : $(PARCLIENT) 102 | $(CC) $(FLAGS) -c parcp.c 103 | 104 | shell_parcp.o : $(PARCLIENT) 105 | $(CC) $(SHELL_FLAGS) -c parcp.c -o shell_parcp.o 106 | 107 | server_parcp.o : $(PARCLIENT) 108 | $(CC) -DPARCP_SERVER $(FLAGS) -c parcp.c -o server_parcp.o 109 | 110 | shell.o : shell.c shell.h 111 | $(CC) $(SHELL_FLAGS) -c shell.c 112 | 113 | box.o : box.c box.h 114 | $(CC) $(SHELL_FLAGS) -c box.c 115 | 116 | menu.o : menu.c menu.h 117 | $(CC) $(SHELL_FLAGS) -c menu.c 118 | 119 | viewer.o : viewer.c viewer.h 120 | $(CC) $(SHELL_FLAGS) -c viewer.c 121 | 122 | global.o : global.c global.h 123 | $(CC) $(SHELL_FLAGS) -c global.c 124 | 125 | match.o : match.c match.h 126 | $(CC) $(FLAGS) -c match.c 127 | 128 | parcp-usb.o : parcp-usb.c parcp-usb.h 129 | $(CC) $(FLAGS) -c parcp-usb.c 130 | 131 | cfgopts.o : cfgopts.c cfgopts.h 132 | $(CC) $(FLAGS) -c cfgopts.c 133 | 134 | -------------------------------------------------------------------------------- /src/match.h: -------------------------------------------------------------------------------- 1 | /* 2 | EPSHeader 3 | 4 | File: match.h 5 | Author: J. Kercheval 6 | Created: Sat, 01/05/1991 22:27:18 7 | */ 8 | /* 9 | EPSRevision History 10 | 11 | J. Kercheval Wed, 02/20/1991 22:28:37 Released to Public Domain 12 | J. Kercheval Sun, 03/10/1991 18:02:56 add is_valid_pattern 13 | J. Kercheval Sun, 03/10/1991 18:25:48 add error_type in is_valid_pattern 14 | J. Kercheval Sun, 03/10/1991 18:47:47 error return from matche() 15 | J. Kercheval Tue, 03/12/1991 22:24:49 Released as V1.1 to Public Domain 16 | */ 17 | 18 | #include /* specialne pro toupper() */ 19 | #include "element.h" /* specialne pro MYBOOL */ 20 | /* 21 | #ifndef MYBOOL 22 | # define MYBOOL int 23 | # define TRUE 1 24 | # define FALSE 0 25 | #endif 26 | */ 27 | 28 | /* 29 | Wildcard Pattern Matching 30 | */ 31 | 32 | /* match defines */ 33 | #define MATCH_PATTERN 6 /* bad pattern */ 34 | #define MATCH_LITERAL 5 /* match failure on literal match */ 35 | #define MATCH_RANGE 4 /* match failure on [..] construct */ 36 | #define MATCH_ABORT 3 /* premature end of text string */ 37 | #define MATCH_END 2 /* premature end of pattern string */ 38 | #define MATCH_VALID 1 /* valid match */ 39 | 40 | /* pattern defines */ 41 | #define PATTERN_VALID 0 /* valid pattern */ 42 | #define PATTERN_ESC -1 /* literal escape at end of pattern */ 43 | #define PATTERN_RANGE -2 /* malformed range in [..] construct */ 44 | #define PATTERN_CLOSE -3 /* no end bracket in [..] construct */ 45 | #define PATTERN_EMPTY -4 /* [..] contstruct is empty */ 46 | 47 | /*---------------------------------------------------------------------------- 48 | * 49 | * Match the pattern PATTERN against the string TEXT; 50 | * 51 | * match() returns TRUE if pattern matches, FALSE otherwise. 52 | * matche() returns MATCH_VALID if pattern matches, or an errorcode 53 | * as follows otherwise: 54 | * 55 | * MATCH_PATTERN - bad pattern 56 | * MATCH_LITERAL - match failure on literal mismatch 57 | * MATCH_RANGE - match failure on [..] construct 58 | * MATCH_ABORT - premature end of text string 59 | * MATCH_END - premature end of pattern string 60 | * MATCH_VALID - valid match 61 | * 62 | * 63 | * A match means the entire string TEXT is used up in matching. 64 | * 65 | * In the pattern string: 66 | * `*' matches any sequence of characters (zero or more) 67 | * `?' matches any character 68 | * [SET] matches any character in the specified set, 69 | * [!SET] or [^SET] matches any character not in the specified set. 70 | * 71 | * A set is composed of characters or ranges; a range looks like 72 | * character hyphen character (as in 0-9 or A-Z). [0-9a-zA-Z_] is the 73 | * minimal set of characters allowed in the [..] pattern construct. 74 | * Other characters are allowed (ie. 8 bit characters) if your system 75 | * will support them. 76 | * 77 | * To suppress the special syntactic significance of any of `[]*?!^-\', 78 | * and match the character exactly, precede it with a `\'. 79 | * 80 | ----------------------------------------------------------------------------*/ 81 | 82 | MYBOOL match(char *pattern, char *text, MYBOOL case_sensitive); 83 | 84 | int matche(register char *pattern, register char *text, MYBOOL case_sensitive); 85 | 86 | /*---------------------------------------------------------------------------- 87 | * 88 | * Return TRUE if PATTERN has any special wildcard characters 89 | * 90 | ----------------------------------------------------------------------------*/ 91 | 92 | MYBOOL is_pattern (char *pattern); 93 | 94 | /*---------------------------------------------------------------------------- 95 | * 96 | * Return TRUE if PATTERN has is a well formed regular expression according 97 | * to the above syntax 98 | * 99 | * error_type is a return code based on the type of pattern error. Zero is 100 | * returned in error_type if the pattern is a valid one. error_type return 101 | * values are as follows: 102 | * 103 | * PATTERN_VALID - pattern is well formed 104 | * PATTERN_ESC - pattern has invalid escape ('\' at end of pattern) 105 | * PATTERN_RANGE - [..] construct has a no end range in a '-' pair (ie [a-]) 106 | * PATTERN_CLOSE - [..] construct has no end bracket (ie [abc-g ) 107 | * PATTERN_EMPTY - [..] construct is empty (ie []) 108 | * 109 | ----------------------------------------------------------------------------*/ 110 | 111 | MYBOOL is_valid_pattern (char *pattern, int *error_type); 112 | -------------------------------------------------------------------------------- /src/Makefile.mint: -------------------------------------------------------------------------------- 1 | DEBUG = 2 | #DEBUG = -DDEBUG 3 | #DEBUG = -DDEBUG -DLOWDEBUG 4 | #DEBUG = -DDEBUG -DLOWDEBUG -DIODEBUG 5 | 6 | FLAGS = $(EXT_FLAGS) -O2 -DATARI $(DEBUG) -Wall -fomit-frame-pointer -fno-strength-reduce 7 | FLAGS030 = -m68020-40 $(FLAGS) 8 | 9 | PARCLIENT = parcp.c parcp.h cfgopts.h parcplow.h parcplow.c crc32.c parcommo.c parftpcl.c sort.c 10 | 11 | ZAKL_OBJS = match.o cfgopts.o parcp68k.o global.o 12 | ZAKL_OBJS030 = match030.o cfgopts030.o parcp68k.o global.o 13 | 14 | OBJS = parcp.o $(ZAKL_OBJS) 15 | OBJS030 = parcp030.o $(ZAKL_OBJS030) 16 | SEROBJS = server_parcp.o $(ZAKL_OBJS) 17 | SEROBJS030 = server_parcp030.o $(ZAKL_OBJS030) 18 | 19 | SHELL_FLAGS = -DSHELL $(FLAGS) 20 | SHELL_FLAGS030 = -DSHELL $(FLAGS030) 21 | SHELL_OBJS = shell_parcp.o shell.o box.o menu.o viewer.o $(ZAKL_OBJS) 22 | SHELL_OBJS030 = shell_parcp030.o shell030.o box030.o menu030.o viewer030.o $(ZAKL_OBJS030) 23 | 24 | parshell : $(SHELL_OBJS) 25 | gcc $(SHELL_FLAGS) -o parcp $(SHELL_OBJS) -lpanel -lncurses 26 | strip parcp 27 | fixstk 64k parcp 28 | 29 | parshell030 : $(SHELL_OBJS030) 30 | gcc $(SHELL_FLAGS030) -o parcp030 $(SHELL_OBJS030) -lpanel -lncurses -L/usr/lib/m68020 31 | strip parcp030 32 | fixstk 64k parcp030 33 | 34 | parcp : $(OBJS) 35 | gcc $(FLAGS) -o parcp $(OBJS) 36 | strip parcp 37 | fixstk 64k parcp 38 | 39 | parcp030 : $(OBJS030) 40 | gcc $(FLAGS030) -o parcp030 $(OBJS030) -L/usr/lib/m68020 41 | strip parcp030 42 | fixstk 64k parcp030 43 | 44 | parserve : $(SEROBJS) 45 | gcc $(FLAGS) -o parserve $(SEROBJS) 46 | strip parserve 47 | fixstk 32k parserve 48 | 49 | parserve030 : $(SEROBJS030) 50 | gcc $(FLAGS030) -o parser30 $(SEROBJS030) -L/usr/lib/m68020 51 | strip parser30 52 | fixstk 32k parser30 53 | 54 | par_io : par_io.c 55 | gcc $(FLAGS) par_io.c -o par_io 56 | strip par_io 57 | 58 | par_in : parinout.c parcp.h 59 | gcc $(FLAGS) -DIN parinout.c -o par_in 60 | strip par_in 61 | fixstk 16384 par_in 62 | 63 | par_out : parinout.c parcp.h 64 | gcc $(FLAGS) -DOUT parinout.c -o par_out 65 | strip par_out 66 | fixstk 16384 par_out 67 | 68 | partest : partest.o $(ZAKL_OBJS) 69 | gcc $(FLAGS) -o partest partest.o $(ZAKL_OBJS) 70 | strip partest 71 | fixstk 64k partest 72 | 73 | all : parshell parshell030 parserve parserve030 par_in 74 | 75 | tgz : all 76 | mv parcp parcp.ttp 77 | mv parcp030 parcp030.ttp 78 | mv parserve parserve.tos 79 | mv parser30 parser30.tos 80 | mv par_in par_in.prg 81 | tar czvf parcp.tgz parcp.ttp parcp030.ttp parserve.tos parser30.tos par_in.prg 82 | rm parcp.ttp parcp030.ttp parserve.tos parser30.tos par_in.prg 83 | 84 | clean : 85 | rm -f *.o parshell parshell030 parserve parserve030 par_in parcp.ttp parcp030.ttp parserve.tos parser30.tos par_in.prg parcp.tgz 86 | 87 | ############################### 88 | 89 | parcp.o : $(PARCLIENT) 90 | gcc $(FLAGS) -c parcp.c 91 | 92 | partest.o : partest.c $(PARCLIENT) 93 | gcc $(FLAGS) -c partest.c 94 | 95 | shell_parcp.o : $(PARCLIENT) 96 | gcc $(SHELL_FLAGS) -c parcp.c -o shell_parcp.o 97 | 98 | server_parcp.o : $(PARCLIENT) 99 | gcc -DPARCP_SERVER $(FLAGS) -c parcp.c -o server_parcp.o 100 | 101 | shell.o : shell.c shell.h parcp.h cfgopts.h 102 | gcc $(SHELL_FLAGS) -c shell.c 103 | 104 | box.o : box.c box.h shell.h 105 | gcc $(SHELL_FLAGS) -c box.c 106 | 107 | menu.o : menu.c menu.h shell.h 108 | gcc $(SHELL_FLAGS) -c menu.c 109 | 110 | viewer.o : viewer.c 111 | gcc $(SHELL_FLAGS) -c viewer.c 112 | 113 | global.o : global.c global.h 114 | gcc $(SHELL_FLAGS) -c global.c 115 | 116 | parcp68k.o : parcp68k.asm 117 | vasm -quiet -Faout -o parcp68k.o -x parcp68k.asm 118 | 119 | match.o : match.c match.h 120 | gcc $(FLAGS) -c match.c 121 | 122 | cfgopts.o : cfgopts.c cfgopts.h 123 | gcc $(FLAGS) -c cfgopts.c 124 | 125 | parcp030.o : $(PARCLIENT) 126 | gcc $(FLAGS030) -c parcp.c -o parcp030.o 127 | 128 | shell_parcp030.o : $(PARCLIENT) 129 | gcc $(SHELL_FLAGS030) -c parcp.c -o shell_parcp030.o 130 | 131 | shell030.o : shell.c parcp.h cfgopts.h menu.c viewer.c box.c 132 | gcc $(SHELL_FLAGS030) -c shell.c -o shell030.o 133 | 134 | box030.o : box.c box.h 135 | gcc $(SHELL_FLAGS030) -c box.c -o box030.o 136 | 137 | menu030.o : menu.c menu.h 138 | gcc $(SHELL_FLAGS030) -c menu.c -o menu030.o 139 | 140 | viewer030.o : viewer.c viewer.h 141 | gcc $(SHELL_FLAGS030) -c viewer.c -o viewer030.o 142 | 143 | server_parcp030.o : $(PARCLIENT) 144 | gcc -DPARCP_SERVER $(FLAGS030) -c parcp.c -o server_parcp030.o 145 | 146 | match030.o : match.c match.h 147 | gcc $(FLAGS030) -c match.c -o match030.o 148 | 149 | cfgopts030.o : cfgopts.c cfgopts.h 150 | gcc $(FLAGS030) -c cfgopts.c -o cfgopts030.o 151 | 152 | -------------------------------------------------------------------------------- /src/sort.c: -------------------------------------------------------------------------------- 1 | /********************************************************/ 2 | /* dir/file list sorting */ 3 | /********************************************************/ 4 | int sgn(int cislo) 5 | { 6 | if (cislo > 0) 7 | return 1; 8 | else if (cislo < 0) 9 | return -1; 10 | else 11 | return 0; 12 | } 13 | 14 | int comp_uni(const char *r1, const char *r2, int odkud, int kolik) 15 | { 16 | int porovnano; 17 | 18 | if (_sort_case) 19 | porovnano = strncmp(r1+odkud, r2+odkud, kolik); 20 | else 21 | porovnano = strncasecmp(r1+odkud, r2+odkud, kolik); 22 | 23 | return sgn(porovnano); 24 | } 25 | 26 | int comp_name(const char *a, const char *b) 27 | { 28 | return comp_uni(a, b, 0, MAXFNAME); 29 | } 30 | int icomp_name(const char *a, const char *b) 31 | { 32 | return - comp_name(a, b); 33 | } 34 | 35 | int hledej_tecku(const char *radek, int pokud) 36 | { 37 | register int i; 38 | for(i=pokud-1; i>0; i--) 39 | if (radek[i] == '.') 40 | return i; 41 | return -1; 42 | } 43 | 44 | int comp_ext(const char *r1, const char *r2) 45 | { 46 | int porovnat; 47 | int odkud1, odkud2, kolik; 48 | 49 | odkud1 = hledej_tecku(r1, MAXFNAME); 50 | odkud2 = hledej_tecku(r2, MAXFNAME); 51 | 52 | if (odkud1 >= 0 && odkud2 >= 0) /* both files have extensions */ 53 | { 54 | int min1 = MAXFNAME-odkud1; 55 | int min2 = MAXFNAME-odkud2; 56 | kolik = min1 < min2 ? min1 : min2; /* common part */ 57 | porovnat = comp_uni(r1+odkud1, r2+odkud2, 0, kolik); 58 | if (porovnat == 0) { /* beginning of extension is same */ 59 | porovnat = sgn(odkud1 - odkud2); /* different extensions length */ 60 | if (porovnat == 0) /* extensions are the same, the names will resolve */ 61 | porovnat = comp_uni(r1, r2, 0, MAXFNAME); 62 | } 63 | } 64 | 65 | else if (odkud1 < 0 && odkud2 < 0) /* no extensions - names will resolve */ 66 | porovnat = comp_uni(r1, r2, 0, MAXFNAME); 67 | 68 | else /* only one with extension */ 69 | { 70 | if (odkud2 < 0) 71 | porovnat = 1; 72 | else 73 | porovnat = -1; 74 | } 75 | 76 | return porovnat; 77 | } 78 | 79 | int icomp_ext(const char *a, const char *b) 80 | { 81 | return - comp_ext(a, b); 82 | } 83 | 84 | int comp_size(const char *a, const char *b) 85 | { 86 | return comp_uni(a, b, MAXFNAME, 10); 87 | } 88 | int icomp_size(const char *a, const char *b) 89 | { 90 | return - comp_size(a, b); 91 | } 92 | 93 | int comp_date(const char *a, const char *b) 94 | { 95 | return comp_uni(a, b, MAXFNAME+12, 16); 96 | } 97 | int icomp_date(const char *a, const char *b) 98 | { 99 | return - comp_date(a, b); 100 | } 101 | 102 | void swap_lines(char *r1, char *r2) 103 | { 104 | char tmpradek[DIRLINELEN]; 105 | memcpy(tmpradek, r1, DIRLINELEN); 106 | memcpy(r1, r2, DIRLINELEN); 107 | memcpy(r2, tmpradek, DIRLINELEN); 108 | } 109 | 110 | /* 111 | ** ssort() -- Fast, small, qsort()-compatible Shell sort 112 | ** 113 | ** by Ray Gardner, public domain 5/90 114 | */ 115 | 116 | #define SWAP(a, b) ((*swap)((void *)(a), (void *)(b))) 117 | 118 | #define COMP(a, b) ((*comp)((void *)(a), (void *)(b))) 119 | 120 | void parcp_sort(void *base, size_t nel, size_t width, 121 | int (*comp) (const void *, const void *), 122 | void (*swap) (void *, void *)) 123 | { 124 | size_t wnel, gap, wgap, i, j; 125 | char *a, *b; 126 | 127 | wnel = width * nel; 128 | for (gap = 0; ++gap < nel;) 129 | gap *= 3; 130 | while (gap /= 3) { 131 | wgap = width * gap; 132 | for (i = wgap; i < wnel; i += width) { 133 | for (j = i - wgap;; j -= wgap) { 134 | a = j + (char *) base; 135 | b = a + wgap; 136 | if (COMP(a, b) <= 0) 137 | break; 138 | SWAP(a,b); 139 | if (j < wgap) 140 | break; 141 | } 142 | } 143 | } 144 | } 145 | 146 | void setrid_obsah(char *zacatek, int a, int b, char jak) 147 | { 148 | void *comp_ptr, *swap_ptr; 149 | 150 | switch(jak) { 151 | case 'N': comp_ptr = comp_name; break; 152 | case 'n': comp_ptr = icomp_name; break; 153 | case 'E': comp_ptr = comp_ext; break; 154 | case 'e': comp_ptr = icomp_ext; break; 155 | case 'S': comp_ptr = comp_size; break; 156 | case 's': comp_ptr = icomp_size; break; 157 | /* timestamp in different order (Thing like) */ 158 | case 'D': comp_ptr = icomp_date; break; 159 | case 'd': comp_ptr = comp_date; break; 160 | 161 | default: return; /* should be unsorted */ 162 | } 163 | swap_ptr = swap_lines; 164 | 165 | parcp_sort(zacatek+a*DIRLINELEN, b-a+1, DIRLINELEN, comp_ptr, swap_ptr); 166 | } 167 | 168 | void dej_adresare_jako_prvni(char *zacatek, int lines) 169 | { 170 | #define _is_dir(i) (*(zacatek+(i)*DIRLINELEN+MAXFNAME+9) == '>') 171 | 172 | int i, j; 173 | 174 | i = 0; 175 | j = lines-1; 176 | while(i <= j) { 177 | if (_is_dir(i) < _is_dir(j)) { 178 | char tmpradek[DIRLINELEN]; 179 | memcpy(tmpradek, zacatek+i*DIRLINELEN, DIRLINELEN); 180 | memcpy(zacatek+i*DIRLINELEN, zacatek+j*DIRLINELEN, DIRLINELEN); 181 | memcpy(zacatek+j*DIRLINELEN, tmpradek, DIRLINELEN); 182 | } 183 | if (_is_dir(i)) 184 | i++; 185 | if (!_is_dir(j)) 186 | j--; 187 | } 188 | 189 | setrid_obsah(zacatek, 0, i-1, toupper(_sort_jak) == 'S' ? 'N' : _sort_jak); /* sort folders */ 190 | 191 | setrid_obsah(zacatek, i, lines-1, _sort_jak); /* sort files */ 192 | } 193 | 194 | void setridit_list_dir(char *buffer) 195 | { 196 | int lines = strlen(buffer) / DIRLINELEN; 197 | if (lines > 1) 198 | dej_adresare_jako_prvni(buffer, lines); 199 | } 200 | -------------------------------------------------------------------------------- /src/parcp68k.asm: -------------------------------------------------------------------------------- 1 | YAMAHA = $ffff8800 * reg. A0 2 | * = $ffff8802 * reg. A1 3 | GPIP = $fffffa01 * reg. A2 4 | CLOCK = $4ba * reg. A3 5 | * = buffer * reg. A4 6 | 7 | * reg. D0 - temporary register 8 | * reg. D1 - keeps original contents of SR 9 | * reg. D2 - counter of remaining length to transmit 10 | * reg. D3 - number 15, for quicker writting to Yamaha regs. 11 | * reg. D4 - Timeout, for quicker adding 12 | 13 | BDIRECT = 7 14 | BSTROBE = 5 15 | 16 | xref _time_out 17 | 18 | RYCHLY = 1 * rychly dotaz na zacatku WAIT_xxx 19 | 20 | RUPT SET 1 * na zacatku jsou preruseni povolena 21 | 22 | CLI MACRO 23 | IFNE RUPT 24 | RUPT SET 0 25 | move.w sr,d1 26 | or.w #$700,sr 27 | ENDC 28 | ENDM 29 | 30 | STI MACRO 31 | IFEQ RUPT 32 | RUPT SET 1 33 | move.w d1,sr 34 | ENDC 35 | ENDM 36 | 37 | SET_CTRL MACRO 38 | CLI 39 | move.b \1,(a0) 40 | move.b #(1<<\2),d0 41 | or.b (a0),d0 42 | move.b d0,(a1) 43 | STI 44 | ENDM 45 | 46 | CLR_CTRL MACRO 47 | CLI 48 | move.b \1,(a0) 49 | move.b #$ff-(1<<\2),d0 50 | and.b (a0),d0 51 | move.b d0,(a1) 52 | STI 53 | ENDM 54 | 55 | SET_INPUT MACRO 56 | CLR_CTRL #7,BDIRECT 57 | ENDM 58 | 59 | SET_OUTPUT MACRO 60 | SET_CTRL #7,BDIRECT 61 | ENDM 62 | 63 | STROBE_HIGH MACRO 64 | SET_CTRL #14,BSTROBE 65 | ENDM 66 | 67 | STROBE_LOW MACRO 68 | CLR_CTRL #14,BSTROBE 69 | ENDM 70 | 71 | IS_READY MACRO 72 | btst #0,(a2) 73 | ENDM 74 | 75 | GET_BYTE MACRO 76 | CLI 77 | move.b d3,(a0) 78 | move.b (a0),(a4)+ 79 | * STI necht STI da az nasledujici STROBE_xxx 80 | ENDM 81 | 82 | PUT_BYTE MACRO 83 | CLI 84 | move.b d3,(a0) 85 | move.b (a4)+,(a1) 86 | * STI necht STI da az nasledujici STROBE_xxxx 87 | ENDM 88 | 89 | WAIT_LOW: MACRO 90 | IFNE RYCHLY 91 | IS_READY * pro urychleni dotaz hned na pocatku 92 | beq.s .end\@ 93 | ENDC 94 | move.l (a3),d0 95 | add.l d4,d0 96 | .loop\@ IS_READY 97 | beq.s .end\@ 98 | cmp.l (a3),d0 99 | bne.s .loop\@ 100 | bra timeout 101 | .end\@ 102 | ENDM 103 | 104 | WAIT_HIGH: MACRO 105 | IFNE RYCHLY 106 | IS_READY * pro urychleni dotaz hned na pocatku 107 | bne.s .end\@ 108 | ENDC 109 | move.l (a3),d0 110 | add.l d4,d0 111 | .loop\@ IS_READY 112 | bne.s .end\@ 113 | cmp.l (a3),d0 114 | bne.s .loop\@ 115 | bra timeout 116 | .end\@ 117 | ENDM 118 | 119 | GODMODE MACRO 120 | clr.l -(sp) 121 | move #32,-(sp) 122 | trap #1 123 | addq #6,sp 124 | move.l d0,zasobnik 125 | ENDM 126 | 127 | USERMODE MACRO 128 | move.l zasobnik,-(sp) 129 | move #32,-(sp) 130 | trap #1 131 | addq #6,sp 132 | ENDM 133 | 134 | SAVE_REGS MACRO 135 | movem.l a2-a4/d2-d4,-(sp) 136 | endm 137 | 138 | RESTORE_REGS MACRO 139 | movem.l (sp)+,a2-a4/d2-d4 140 | ENDM 141 | 142 | prebrat_parametry MACRO 143 | move.l 28(sp),a4 /* odkud */ 144 | move.l 32(sp),d2 /* kolik slov */ 145 | asr.l #1,d2 /* tolik bajtu */ 146 | ENDM 147 | 148 | naloudovat_registry MACRO 149 | lea YAMAHA,a0 150 | lea 2(a0),a1 151 | lea GPIP,a2 152 | lea CLOCK,a3 153 | moveq #15,d3 154 | move.l _time_out,d4 155 | mulu #200,d4 156 | ENDM 157 | 158 | xdef _fast_client_read_block 159 | xdef _fast_client_write_block 160 | xdef _fast_server_read_block 161 | xdef _fast_server_write_block 162 | ********************************************************************* 163 | _fast_client_read_block: 164 | SAVE_REGS 165 | prebrat_parametry 166 | GODMODE 167 | naloudovat_registry 168 | SET_INPUT 169 | bra.s .cyklus 170 | 171 | .cl_re GET_BYTE 172 | .cyklus STROBE_LOW 173 | WAIT_LOW 174 | GET_BYTE 175 | STROBE_HIGH 176 | WAIT_HIGH 177 | subq.l #1,d2 178 | bge.s .cl_re 179 | 180 | .konec USERMODE 181 | RESTORE_REGS 182 | moveq #0,d0 183 | rts 184 | ********************************************************************* 185 | _fast_server_read_block: 186 | SAVE_REGS 187 | prebrat_parametry 188 | GODMODE 189 | naloudovat_registry 190 | SET_INPUT 191 | bra.s .cyklus 192 | 193 | .se_re WAIT_HIGH 194 | GET_BYTE 195 | STROBE_HIGH 196 | .cyklus WAIT_LOW 197 | GET_BYTE 198 | STROBE_LOW 199 | subq.l #1,d2 200 | bge.s .se_re 201 | 202 | .konec WAIT_HIGH 203 | STROBE_HIGH 204 | USERMODE 205 | RESTORE_REGS 206 | moveq #0,d0 207 | rts 208 | ********************************************************************* 209 | _fast_client_write_block: 210 | SAVE_REGS 211 | prebrat_parametry 212 | GODMODE 213 | naloudovat_registry 214 | SET_OUTPUT 215 | bra.s .cyklus 216 | 217 | .cl_wr PUT_BYTE 218 | STROBE_HIGH 219 | WAIT_HIGH 220 | .cyklus PUT_BYTE 221 | STROBE_LOW 222 | WAIT_LOW 223 | subq.l #1,d2 224 | bge.s .cl_wr 225 | 226 | .konec STROBE_HIGH 227 | WAIT_HIGH 228 | SET_INPUT 229 | USERMODE 230 | RESTORE_REGS 231 | moveq #0,d0 232 | rts 233 | ********************************************************************* 234 | _fast_server_write_block: 235 | SAVE_REGS 236 | prebrat_parametry 237 | GODMODE 238 | naloudovat_registry 239 | WAIT_LOW 240 | SET_OUTPUT 241 | bra.s .cyklus 242 | 243 | .se_wr PUT_BYTE 244 | STROBE_HIGH 245 | WAIT_LOW 246 | .cyklus PUT_BYTE 247 | STROBE_LOW 248 | WAIT_HIGH 249 | subq.l #1,d2 250 | bge.s .se_wr 251 | 252 | .konec STROBE_HIGH 253 | SET_INPUT 254 | USERMODE 255 | RESTORE_REGS 256 | moveq #0,d0 257 | rts 258 | ********************************************************************* 259 | timeout: 260 | SET_INPUT 261 | STROBE_HIGH 262 | USERMODE 263 | RESTORE_REGS 264 | moveq #-1,d0 265 | rts 266 | 267 | BSS 268 | zasobnik: 269 | ds.l 1 270 | -------------------------------------------------------------------------------- /src/parcplow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PARallel CoPy - written for transferring large files between any two machines 3 | * with parallel ports. 4 | * 5 | * Petr Stehlik (c) 1996,1997 6 | * 7 | * You need a special HW interface if your PC offers unidirectional parallel 8 | * port only. 9 | */ 10 | 11 | /*******************************************************************************/ 12 | 13 | #ifndef _PARCPLOW_H 14 | #define _PARCPLOW_H 15 | 16 | #ifdef ATARI 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #define clrscr() printf("\033E\033v") 23 | 24 | #define STROBE_HIGH Ongibit(0x20) 25 | #define STROBE_LOW Offgibit(0xcf) 26 | 27 | MYBOOL _is_ready(void) 28 | { 29 | BYTE *GPIP=(BYTE *)0xfffffa01L; 30 | return (*GPIP & 1); 31 | } 32 | #define IS_READY Supexec(_is_ready) 33 | 34 | #define GET_BYTE(x) {x = Giaccess(0,15);} 35 | #define PUT_BYTE(x) (void)Giaccess(x,15|0x80) 36 | 37 | #define SET_INPUT (void)Giaccess(Giaccess(0,7)&~(1 << 7),7|0x80) 38 | #define SET_OUTPUT (void)Giaccess(Giaccess(0,7)| (1 << 7),7|0x80) 39 | 40 | #define KEYPRESSED (Kbshift(-1) & 0x0f) 41 | #define STOP_KEYSTROKE "Shift+Control+Alternate" 42 | 43 | #define ARCHIVE_BIT FA_CHANGED 44 | #endif /* ATARI */ 45 | 46 | /******************************************************************************/ 47 | 48 | #ifdef IBM 49 | # if !defined(_WIN32) && !defined(__APPLE__) 50 | # include 51 | # endif 52 | 53 | // general things 54 | #ifdef __MSDOS__ 55 | //extern __Go32_Info_Block _go32_info_block; 56 | 57 | int __opendir_flags = __OPENDIR_PRESERVE_CASE; /* preserve upper/lower filenames */ 58 | 59 | void clrscr(void); 60 | int getch(void); 61 | 62 | #define KEYPRESSED (_farpeekb(_dos_ds, 0x417) & 0x0f) 63 | #define STOP_KEYSTROKE "Shift+Ctrl+Alt" 64 | #define ARCHIVE_BIT _A_ARCH 65 | #define _PATH_MOUNTED "" 66 | 67 | #elif defined _WIN32 68 | 69 | #define clrscr() system("cls") 70 | #define STOP_KEYSTROKE "Ctrl-C" 71 | #define ARCHIVE_BIT _A_ARCH /* ?? */ 72 | 73 | #else 74 | 75 | #define __LINUX__ 76 | #define clrscr() 77 | #define STOP_KEYSTROKE "Ctrl-C" 78 | #define ARCHIVE_BIT 0x0020 /* needs to be implemented with mtime/atime */ 79 | #endif 80 | 81 | // communication 82 | #ifdef USB 83 | 84 | #include "parcp-usb.h" 85 | #define STROBE_HIGH set_strobe(1) 86 | #define STROBE_LOW set_strobe(0); 87 | #define IS_READY get_busy() 88 | #define GET_BYTE(x) 89 | #define PUT_BYTE(x) 90 | #define SET_OUTPUT set_mode(1); 91 | #define SET_INPUT set_mode(0); 92 | 93 | #else /* !USB */ 94 | 95 | #define CFG_PORT "Port" 96 | #define CFG_UNIBI "UNI-BI" 97 | 98 | MYBOOL PCunidirect = FALSE; 99 | int print_port = 0x378; 100 | int port_type = 1; /* 0 = SPP, 1 = bidir/EPP, 2 = ECP2EPP */ 101 | int cable_type = 1; /* 0 = LapLink, 1 = bidirectional */ 102 | int old_ecp_val; /* the value of the ECP register saved during the PARCP run */ 103 | 104 | #define ECP2EPP \ 105 | { \ 106 | iopl(3); \ 107 | old_ecp_val = inportb(print_port + 0x402); \ 108 | outportb(print_port + 0x402,0x80); \ 109 | iopl(0); \ 110 | } 111 | 112 | #define EPP2ECP \ 113 | { \ 114 | iopl(3); \ 115 | outportb(print_port+0x402,old_ecp_val); \ 116 | iopl(0); \ 117 | } 118 | 119 | #ifdef __MSDOS__ 120 | #include 121 | #include 122 | #include 123 | #include 124 | #include 125 | #define iopl(a) /* pro DOS je to nic */ 126 | #else /* ! __MSDOS__ */ 127 | #include 128 | #include 129 | void outportb(a,b) {outb(b,a);} 130 | BYTE inportb(a) {return inb(a);} 131 | #endif /* !__MSDOS__ alias Linux */ 132 | 133 | int gcontrol = (1 << 2); /* Ucc */ 134 | 135 | #define SET_GCONTROL(x) { gcontrol |= (1 << x); } 136 | #define CLR_GCONTROL(x) { gcontrol &=~(1 << x); } 137 | #define SET_CTRL(x) \ 138 | { \ 139 | SET_GCONTROL(x); \ 140 | outportb(print_port+2, gcontrol); \ 141 | } 142 | #define CLR_CTRL(x) \ 143 | { \ 144 | CLR_GCONTROL(x); \ 145 | outportb(print_port+2, gcontrol); \ 146 | } 147 | #define STATUS inportb(print_port+1) 148 | 149 | /* POST PC: STROBE, AUTOLF, INIT are +5V, while SLCTIN is 0V) */ 150 | /* STROBE is 0. bit and is negated - log.1 = 0V, log.0 = +5V */ 151 | /* AUTOLF is 1. bit and is negated - log.1 = 0V, log.0 = +5V */ 152 | /* SLCTIN is 3. bit and is negated - log.1 = 0V, log.0 = +5V */ 153 | /* INIT is 2. bit, log.1 = +5V, which gives current to the intelligent UNI-BI interface */ 154 | 155 | #define STROBE_HIGH \ 156 | { \ 157 | if (cable_type) { \ 158 | CLR_CTRL(0); \ 159 | } \ 160 | else { \ 161 | outportb(print_port, 0x10); \ 162 | } \ 163 | } 164 | 165 | #define FIX_GCONTROL_STROBE_HIGH \ 166 | { \ 167 | if (cable_type) { \ 168 | CLR_GCONTROL(0); \ 169 | } \ 170 | } 171 | 172 | #define STROBE_LOW \ 173 | { \ 174 | if (cable_type) { \ 175 | SET_CTRL(0); \ 176 | } \ 177 | else { \ 178 | outportb(print_port, 0); \ 179 | } \ 180 | } 181 | 182 | 183 | #define IS_READY !(STATUS & 0x80) 184 | 185 | #define CLOCK_LOW SET_CTRL(3) 186 | #define CLOCK_HIGH CLR_CTRL(3) 187 | #define CLOCK_RAISE {CLOCK_LOW; CLOCK_HIGH;} /* impuls for the latch to copy the data on the output */ 188 | #define GET_LOW_NIBBLE ((STATUS >> 3) & 0x0f) 189 | #define GET_HIGH_NIBBLE ((STATUS << 1) & 0xf0) 190 | 191 | #define GET_BYTE(x) \ 192 | { \ 193 | if (PCunidirect) { \ 194 | CLOCK_LOW; \ 195 | x=GET_LOW_NIBBLE; \ 196 | CLOCK_HIGH; \ 197 | x|=GET_HIGH_NIBBLE; \ 198 | } \ 199 | else { \ 200 | x=inportb(print_port); \ 201 | } \ 202 | } 203 | 204 | #define PUT_BYTE(x) \ 205 | { \ 206 | outportb(print_port, x); \ 207 | if (PCunidirect) { \ 208 | CLOCK_RAISE; \ 209 | } \ 210 | } 211 | 212 | #define SET_OUTPUT \ 213 | { \ 214 | if (cable_type) \ 215 | { \ 216 | if (PCunidirect) { \ 217 | SET_CTRL(1); \ 218 | } \ 219 | else { \ 220 | CLR_CTRL(5); \ 221 | } \ 222 | } \ 223 | } 224 | 225 | #define SET_INPUT \ 226 | { \ 227 | if (cable_type) \ 228 | { \ 229 | if (PCunidirect) { \ 230 | CLR_CTRL(1); \ 231 | } \ 232 | else { \ 233 | SET_CTRL(5); \ 234 | } \ 235 | } \ 236 | } 237 | 238 | long laplink_client_read_block(BYTE *block, long n); 239 | long laplink_server_read_block(BYTE *block, long n); 240 | long laplink_client_write_block(const BYTE *block, long n); 241 | long laplink_server_write_block(const BYTE *block, long n); 242 | 243 | #endif /* USB */ 244 | 245 | #endif /* IBM */ 246 | /*******************************************************************************/ 247 | #ifdef STANDALONE 248 | 249 | #undef SET_INPUT 250 | #undef SET_OUTPUT 251 | #undef STROBE_HIGH 252 | #undef STROBE_LOW 253 | #undef IS_READY 254 | #undef GET_BYTE 255 | #undef PUT_BYTE 256 | #undef ECP2EPP 257 | #undef EPP2ECP 258 | 259 | #define SET_INPUT {} 260 | #define SET_OUTPUT {} 261 | #define STROBE_HIGH {} 262 | #define STROBE_LOW {} 263 | #define IS_READY FALSE 264 | #define GET_BYTE(x) 0 265 | #define PUT_BYTE(x) {} 266 | #define ECP2EPP 267 | #define EPP2ECP 268 | 269 | #endif 270 | 271 | #endif /* _PARCPLOW_H */ 272 | -------------------------------------------------------------------------------- /src/parcplow.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int time_out; 4 | 5 | #define WAIT_LOW {int i=TIMER+time_out; while(IS_READY) if (TIMER>i) {SET_INPUT;STROBE_HIGH;return -1;};} 6 | #define WAIT_HIGH {int i=TIMER+time_out; while(! IS_READY) if (TIMER>i) {SET_INPUT;STROBE_HIGH;return -1;};} 7 | 8 | long client_read_block(BYTE *block, long n) 9 | { 10 | #ifdef ATARI 11 | if (_assembler) 12 | return fast_client_read_block(block, n); 13 | #elif defined(IBM) 14 | # ifdef USB 15 | long offset = 0; 16 | long ret = usb_set_client_read_size(n); 17 | while(ret == 0 && n > 0) { 18 | unsigned lbl = USB_BLOCK_SIZE - (offset == 0 ? 1 : 0); 19 | if (lbl > n) lbl = n; 20 | ret = usb_read_block(block, offset, lbl); 21 | offset += lbl; 22 | n -= lbl; 23 | } 24 | return ret; 25 | # else 26 | if (!cable_type) 27 | return laplink_client_read_block(block, n); 28 | # endif 29 | #endif 30 | 31 | #ifndef USB 32 | { 33 | BYTE x; 34 | long i = 0; 35 | 36 | SET_INPUT; 37 | STROBE_LOW; 38 | 39 | while(TRUE) { 40 | LDPRINT("l STROBE is LOW, waiting for LOW\n"); 41 | WAIT_LOW; 42 | GET_BYTE(x); 43 | block[i++]=x; 44 | LDPRINT1("l 1st byte = $%x, STROBE is HIGH, waiting for HIGH\n",x); 45 | STROBE_HIGH; 46 | WAIT_HIGH; 47 | if (i>=n) 48 | break; 49 | 50 | GET_BYTE(x); 51 | block[i++]=x; 52 | LDPRINT1("l 2nd byte = $%x\n",x); 53 | STROBE_LOW; 54 | } 55 | return 0; 56 | } 57 | #endif 58 | } 59 | 60 | long server_read_block(BYTE *block, long n) 61 | { 62 | #ifdef ATARI 63 | if (_assembler) 64 | return fast_server_read_block(block, n); 65 | #elif defined(IBM) 66 | # ifdef USB 67 | long offset = 0; 68 | long ret = usb_set_server_read_size(n); 69 | while(ret == 0 && n > 0) { 70 | unsigned lbl = USB_BLOCK_SIZE - (offset == 0 ? 1 : 0); 71 | if (lbl > n) lbl = n; 72 | ret = usb_read_block(block, offset, lbl); 73 | offset += lbl; 74 | n -= lbl; 75 | } 76 | return ret; 77 | # else 78 | if (!cable_type) 79 | return laplink_server_read_block(block, n); 80 | # endif 81 | #endif 82 | 83 | #ifndef USB 84 | { 85 | BYTE x; 86 | long i = 0; 87 | 88 | SET_INPUT; 89 | 90 | while(TRUE) { 91 | LDPRINT("l Waiting for LOW\n"); 92 | WAIT_LOW; 93 | 94 | GET_BYTE(x); 95 | block[i++]=x; 96 | LDPRINT1("l 1st byte = $%x, STROBE is LOW\n",x); 97 | STROBE_LOW; 98 | LDPRINT("l Waiting for HIGH\n"); 99 | WAIT_HIGH; 100 | 101 | if (i>=n) 102 | break; 103 | 104 | GET_BYTE(x); 105 | block[i++]=x; 106 | LDPRINT1("l 2nd byte = $%x, STROBE is HIGH\n",x); 107 | STROBE_HIGH; 108 | } 109 | LDPRINT("l STROBE is HIGH\n"); 110 | STROBE_HIGH; 111 | return 0; 112 | } 113 | #endif 114 | } 115 | 116 | long client_write_block(const BYTE *block, long n) 117 | { 118 | #ifdef ATARI 119 | if (_assembler) 120 | return fast_client_write_block(block, n); 121 | #elif defined(IBM) 122 | # ifdef USB 123 | long offset = 0; 124 | unsigned lbl = USB_BLOCK_SIZE - 1; 125 | if (lbl > n) lbl = n; 126 | long ret = usb_set_client_write_size(n, block); 127 | offset += lbl; 128 | n -= lbl; 129 | while(ret == 0 && n > 0) { 130 | lbl = USB_BLOCK_SIZE; 131 | if (lbl > n) lbl = n; 132 | ret = usb_write_block(block, offset, lbl); 133 | offset += lbl; 134 | n -= lbl; 135 | } 136 | return ret; 137 | # else 138 | if (!cable_type) 139 | return laplink_client_write_block(block, n); 140 | # endif 141 | #endif 142 | 143 | #ifndef USB 144 | { 145 | BYTE x; 146 | long i = 0; 147 | 148 | #ifdef IODEBUG 149 | GET_BYTE(x); 150 | if (x != 0xff) { 151 | LDPRINT("! WARNING! Other side is not receiving!"); 152 | return -1; 153 | } 154 | #endif 155 | 156 | SET_OUTPUT; 157 | 158 | while(TRUE) { 159 | PUT_BYTE(x=block[i++]); 160 | LDPRINT1("l 1st byte = $%x, STROBE is LOW, waiting for LOW\n",x); 161 | STROBE_LOW; 162 | WAIT_LOW; 163 | 164 | if (i>=n) 165 | break; 166 | 167 | PUT_BYTE(x=block[i++]); 168 | LDPRINT1("l 2nd byte = $%x, STROBE is HIGH, waiting for HIGH\n",x); 169 | STROBE_HIGH; 170 | WAIT_HIGH; 171 | } 172 | LDPRINT("l STROBE is HIGH, waiting for HIGH\n"); 173 | STROBE_HIGH; 174 | WAIT_HIGH; 175 | SET_INPUT; 176 | return 0; 177 | } 178 | #endif 179 | } 180 | 181 | long server_write_block(const BYTE *block, long n) 182 | { 183 | #ifdef ATARI 184 | if (_assembler) 185 | return fast_server_write_block(block, n); 186 | #elif defined(IBM) 187 | # ifdef USB 188 | long offset = 0; 189 | unsigned lbl = USB_BLOCK_SIZE - 1; 190 | if (lbl > n) lbl = n; 191 | long ret = usb_set_server_write_size(n, block); 192 | offset += lbl; 193 | n -= lbl; 194 | while(ret == 0 && n > 0) { 195 | lbl = USB_BLOCK_SIZE; 196 | if (lbl > n) lbl = n; 197 | ret = usb_write_block(block, offset, lbl); 198 | offset += lbl; 199 | n -= lbl; 200 | } 201 | return ret; 202 | # else 203 | if (!cable_type) 204 | return laplink_server_write_block(block, n); 205 | # endif 206 | #endif 207 | 208 | #ifndef USB 209 | { 210 | BYTE x; 211 | long i = 0; 212 | 213 | LDPRINT("l Waiting for LOW\n"); 214 | WAIT_LOW; 215 | 216 | #ifdef IODEBUG 217 | GET_BYTE(x); 218 | if (x != 0xff) { 219 | LDPRINT("! WARNING! Other side is not receiving!"); 220 | return -1; 221 | } 222 | #endif 223 | 224 | SET_OUTPUT; 225 | 226 | while(TRUE) { 227 | PUT_BYTE(x=block[i++]); 228 | LDPRINT1("l 1st byte = $%x, STROBE is LOW, waiting for HIGH\n",x); 229 | STROBE_LOW; 230 | WAIT_HIGH; 231 | 232 | if (i>=n) 233 | break; 234 | 235 | PUT_BYTE(x=block[i++]); 236 | LDPRINT1("l 2nd byte = $%x, STROBE is HIGH, waiting for LOW\n",x); 237 | STROBE_HIGH; 238 | WAIT_LOW; 239 | } 240 | STROBE_HIGH; 241 | LDPRINT("l Write_block: STROBE is HIGH\n"); 242 | SET_INPUT; 243 | return 0; 244 | } 245 | #endif 246 | } 247 | 248 | /* ---------------------------------------------------------------------- */ 249 | #if defined(IBM) && !defined(USB) 250 | 251 | long laplink_client_read_block(BYTE *block, long n) 252 | { 253 | BYTE x; 254 | long i = 0; 255 | 256 | while(TRUE) { 257 | LDPRINT("l STROBE is LOW, waiting for LOW\n"); 258 | STROBE_LOW; WAIT_LOW; 259 | x = GET_LOW_NIBBLE; 260 | LDPRINT1("l low nibble = $%x, STROBE is HIGH, waiting for HIGH\n",x); 261 | STROBE_HIGH; WAIT_HIGH; 262 | if (i>=n) 263 | break; 264 | x |= GET_HIGH_NIBBLE; 265 | block[i++]=x; 266 | LDPRINT1("l byte = $%x\n",x); 267 | } 268 | return 0; 269 | } 270 | 271 | long laplink_server_read_block(BYTE *block, long n) 272 | { 273 | BYTE x; 274 | long i = 0; 275 | 276 | while(TRUE) { 277 | LDPRINT("l Waiting for LOW\n"); 278 | WAIT_LOW; 279 | 280 | x = GET_LOW_NIBBLE; 281 | LDPRINT1("l low nibble = $%x, STROBE is LOW\n",x); 282 | STROBE_LOW; 283 | if (i>=n) 284 | break; 285 | LDPRINT("l Waiting for HIGH\n"); 286 | WAIT_HIGH; 287 | x |= GET_HIGH_NIBBLE; 288 | block[i++]=x; 289 | LDPRINT1("l byte = $%x, STROBE is HIGH\n",x); 290 | STROBE_HIGH; 291 | } 292 | LDPRINT("l STROBE is LOW, waiting for HIGH\n"); 293 | WAIT_HIGH; 294 | LDPRINT("l STROBE is HIGH\n"); 295 | STROBE_HIGH; 296 | return 0; 297 | } 298 | 299 | long laplink_client_write_block(const BYTE *block, long n) 300 | { 301 | BYTE x; 302 | long i = 0; 303 | 304 | while(TRUE) { 305 | PUT_BYTE((x=block[i])&0x0f); 306 | LDPRINT1("l low nibble = $%x, STROBE is LOW, waiting for LOW\n",x); 307 | WAIT_LOW; 308 | 309 | if (i>=n) 310 | break; 311 | 312 | PUT_BYTE(0x10 | x>>4); 313 | i++; 314 | LDPRINT1("l byte = $%x, STROBE is HIGH, waiting for HIGH\n",x); 315 | WAIT_HIGH; 316 | } 317 | LDPRINT("l STROBE is HIGH, waiting for HIGH\n"); 318 | STROBE_HIGH; 319 | WAIT_HIGH; 320 | return 0; 321 | } 322 | 323 | long laplink_server_write_block(const BYTE *block, long n) 324 | { 325 | BYTE x; 326 | long i = 0; 327 | 328 | LDPRINT("l Waiting for LOW\n"); 329 | WAIT_LOW; 330 | 331 | while(TRUE) { 332 | PUT_BYTE((x=block[i]) & 0x0f); 333 | LDPRINT1("l low nibble = $%x, STROBE is LOW, waiting for HIGH\n",x); 334 | WAIT_HIGH; 335 | 336 | if (i>=n) 337 | break; 338 | 339 | PUT_BYTE(0x10 | x>>4); 340 | i++; 341 | LDPRINT1("l byte = $%x, STROBE is HIGH, waiting for LOW\n",x); 342 | WAIT_LOW; 343 | } 344 | STROBE_HIGH; 345 | LDPRINT("l Write_block: STROBE is HIGH\n"); 346 | return 0; 347 | } 348 | 349 | #endif 350 | -------------------------------------------------------------------------------- /src/parcpcfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PARCP configuration file 3 | * 4 | * (c) Petr Stehlik, 1996-2016 5 | */ 6 | 7 | #include "parcp.h" 8 | #include "parcplow.h" 9 | int getche(void); 10 | #include "global.h" 11 | #include "parstruc.h" 12 | #include "parcommo.c" 13 | 14 | void zpracovani_parametru(int argc, char *argv[], char *cesta) 15 | { 16 | MYBOOL konfigOK = FALSE; 17 | 18 | /* nejdrive podle priorit najdu konfiguracni soubor */ 19 | konfigOK = hledej_config(argv, cesta); 20 | 21 | /* zkusim jeste jestli neni cesta ke konfigu na prikazove radce */ 22 | if (argc == 2 && argv[1] != NULL) { 23 | strcpy(cesta, argv[1]); 24 | konfigOK = file_existuje(cesta); 25 | } 26 | 27 | if (konfigOK) { 28 | printf("Reading configuration file: %s\n", cesta); 29 | input_config(cesta, mconfigs, CFGHEAD); 30 | } 31 | else { /* pokud nebyl nalezen konfiguracni soubor, tak ho zkusim vytvorit */ 32 | printf("Configuration file not found.\nIt will be created at: %s\n", cesta); 33 | } 34 | } 35 | 36 | void EXIT(char *a) 37 | { 38 | printf("\n%s", a); 39 | exit(1); 40 | } 41 | 42 | MYBOOL is_bidir(int Port) 43 | { 44 | MYBOOL Ret = FALSE; 45 | BYTE j; 46 | 47 | for(j=127;j;j>>=1) { 48 | outportb(Port, j); 49 | if (inportb(Port) != j) { 50 | Ret = TRUE; 51 | break; 52 | } 53 | } 54 | 55 | return Ret; 56 | } 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | int LPTport; 61 | int Ctrl,Orig; 62 | MYBOOL Ret; 63 | char cfg_file[MAXPATH]; 64 | int ports[3]; 65 | 66 | clrscr(); 67 | setvbuf(stdout,NULL,_IONBF,0); 68 | 69 | puts("PARallel CoPy ConFiGuration - written by Petr Stehlik (c) 1996-2016.\n"\ 70 | "Version "VERZE" (compiled on "__DATE__")\n"); 71 | 72 | zpracovani_parametru(argc, argv, cfg_file); 73 | 74 | puts("\n"\ 75 | "Welcome to PARCP configuration program!\n"\ 76 | "---------------------------------------\n"\ 77 | "Since PARCP works over parallel ports, this program will configure PARCP\n"\ 78 | "according to chosen parallel port. Please read the following instructions\n"\ 79 | "carefully and when in doubt, consult PARCP's documentation or author directly.\n"); 80 | 81 | puts("Please disconnect all peripherals and cables from all parallel (printer) ports\n"\ 82 | "of your computer before you proceed in the configuration program.\n"\ 83 | "If everything is disconnected you might also consider rebooting to clean DOS,\n"\ 84 | "because various resident drivers may distort results of my HW tests.\n"); 85 | 86 | printf("Is everything disconnected from the parallel (printer) ports? (Y/n): "); 87 | if (tolower(getch()) == 'n') 88 | EXIT("\nSo disconnect it and rerun PARCPCFG.EXE."); 89 | printf("\n"); 90 | 91 | puts("\nChecking hardware of this computer...\n"); 92 | 93 | puts("This machine is equipped with:"); 94 | for(LPTport = 0; LPTport < 3; LPTport++) { 95 | int adr = ports[LPTport] = _farpeekw(_dos_ds,(LPTport)*2+0x408); 96 | if (adr) 97 | printf("%d ... parallel port LPT%d (base address: %x)\n", LPTport+1, LPTport+1, adr); 98 | } 99 | 100 | printf("\nEnter the number of parallel port you will use for PARCP: "); 101 | LPTport = getche() - '0'; 102 | printf("\n"); 103 | if (LPTport < 1 || LPTport > 3) 104 | EXIT("Wrong parallel port number."); 105 | 106 | print_port = ports[LPTport-1]; 107 | 108 | if (! print_port) 109 | EXIT("No such parallel port on this machine."); 110 | 111 | puts("\nTesting parallel port...\n"); 112 | 113 | Ctrl = print_port+2; 114 | Orig = inportb(Ctrl); 115 | 116 | /* Try to turn port in */ 117 | #if 1 118 | outportb(Ctrl,32 | Orig); 119 | #else 120 | outportb(Ctrl,32+4); 121 | #endif 122 | Ret = is_bidir(print_port); 123 | /* Turn port back out */ 124 | outportb(Ctrl,Orig); 125 | 126 | if (Ret) /* Bidir or EPP */ 127 | port_type = 1; 128 | else { /* Normal or ECP or ECP/EPP */ 129 | 130 | /* Try to turn port to EPP mode */ 131 | old_ecp_val = inportb(print_port + 0x402); 132 | outportb(print_port + 0x402,0x80); 133 | 134 | outportb(Ctrl,32 | Orig); 135 | Ret = is_bidir(print_port); 136 | /* Turn port back out */ 137 | outportb(Ctrl,Orig); 138 | 139 | /* Turn port back to ECP */ 140 | outportb(print_port+0x402,old_ecp_val); 141 | 142 | if (Ret) /* ECP/EPP port */ 143 | port_type = 2; 144 | else { 145 | port_type = 0; 146 | if ((old_ecp_val & 15) == 5) { 147 | puts(\ 148 | "This port is in the ECP mode and can't be switched into the EPP mode.\n"\ 149 | "PARCP cannot use this type of port for bidirectional transfers.\n"\ 150 | "However you may enter your BIOS setup and look for option of switching\n"\ 151 | "the mode of parallel port. If you find such an option, change it to ECP/EPP,\n"\ 152 | "EPP/SPP or similar and try to run this test again.\n"); 153 | } 154 | } 155 | } 156 | 157 | if (port_type == 0) { 158 | PCunidirect = TRUE; 159 | puts(\ 160 | "Unidirectional port detected. That means you will have to make\n"\ 161 | "and always use the UNI-BI HW adapter (described in documentation)\n"\ 162 | "which will emulate the bidirectional capability of your parallel port.\n"\ 163 | "When you want to connect to a PC, you may also use LapLink cable.\n"); 164 | 165 | puts("Do you want to use your UNI-BI HW adapter and PARCP cable? (Y/n): "); 166 | if (tolower(getch()) == 'n') { 167 | PCunidirect = FALSE; /* NOTE: LapLink cable is required! */ 168 | puts("\n"\ 169 | "OK, but now you have to use LapLink cable only and you cannot connect this\n"\ 170 | "computer to an Atari ST.\n"); 171 | } 172 | } 173 | else { 174 | PCunidirect = FALSE; 175 | puts(\ 176 | "This parallel port seems to have bidirectional capability.\n\n"\ 177 | "For connecting this computer to Atari ST you need just PARCP cable.\n"\ 178 | "For connecting with PC you may use either PARCP or LapLink cable.\n"\ 179 | "Please note that PARCP cable gives you twice the transfer speed compared\n"\ 180 | "to LapLink cable throughput.\n"); 181 | } 182 | 183 | if (PCunidirect) 184 | cable_type = 1; /* s UNI-BI musi mit PARCP kabel */ 185 | else if (port_type == 0 && !PCunidirect) 186 | cable_type = 0; /* na blbem portu bez UNI-BI musi mit LapLink */ 187 | else { 188 | puts(\ 189 | "PARCP is able to use two kinds of parallel cables for connecting two PC's:\n"\ 190 | "0 ... unidirectional LapLink cable (sold in every computer shop)\n"\ 191 | "1 ... PARCP bidirectional cable (for the fastest transfer speed)\n"\ 192 | "Note that for connecting to an Atari ST you always have to use PARCP cable (1)\n"); 193 | 194 | printf("Choose the parallel cable you want to use with PARCP (0/1): "); 195 | cable_type = getche() - '0'; 196 | printf("\n"); 197 | if (cable_type < 0 || cable_type > 1) 198 | EXIT("Wrong parallel cable type."); 199 | } 200 | 201 | /* display new settings */ 202 | puts("\n"\ 203 | "New settings are as follows:\n"\ 204 | "----------------------------"); 205 | printf("Parallel port base address: %x\n", print_port); 206 | printf("Parallel port type: "); 207 | switch(port_type) { 208 | case 0: printf("unidirectional/ECP unable to switch to EPP\n"); break; 209 | case 1: printf("bidirectional/EPP\n"); break; 210 | case 2: printf("ECP switched to EPP\n"); break; 211 | } 212 | printf("Cable type: %s\n", cable_type ? "PARCP bidirectional" : "LapLink"); 213 | if (cable_type) { 214 | if (PCunidirect) 215 | puts("UNI-BI HW parallel adapter has to be plugged into the parallel port"); 216 | else { 217 | if (port_type) 218 | puts("Do not use UNI-BI HW parallel adapter"); 219 | else 220 | EXIT("Bug in PARCPCFG? Contact author."); 221 | } 222 | } 223 | else { 224 | if (PCunidirect) 225 | EXIT("Bug in PARCPCFG? Contact author."); 226 | else 227 | puts("Do not use UNI-BI HW parallel adapter"); 228 | } 229 | 230 | 231 | printf("\nUpdate %s with these settings? (y/N): ", cfg_file); 232 | if (tolower(getch()) == 'y') { 233 | printf("\nUpdating PARCP configuration file..."); 234 | if (update_config(cfg_file, mconfigs, CFGHEAD) < 0) { 235 | printf(" ERROR! PARCP.CFG not updated correctly!\nCheck if the file isn't write-protected and if there's enough free disk space.\n"); 236 | return 1; 237 | } 238 | else 239 | printf("Done.\n"); 240 | } 241 | else 242 | puts("\nConfiguration file unchanged. Bye!"); 243 | return 0; 244 | } 245 | -------------------------------------------------------------------------------- /src/parcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PARallel CoPy - written for transferring large files between any two machines 3 | * with parallel ports. 4 | * 5 | * Petr Stehlik (c) 1996-2023 6 | * 7 | */ 8 | 9 | #ifndef _PARCP_H 10 | #define _PARCP_H 11 | 12 | #define VERZE "4.3.0" /* displays on the screen when PARCP starts */ 13 | 14 | #define PROTOKOL 0x0380 /* UWORD that ensures compatibility of communication protocol between different versions of PARCP */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #ifndef _WIN32 24 | # ifndef __APPLE__ 25 | # include 26 | # endif 27 | # include 28 | # include 29 | #endif 30 | #include 31 | #include /* added for GCC 2.95.2 */ 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "element.h" 38 | 39 | #include "cfgopts.h" 40 | #include "parcperr.h" 41 | 42 | #ifdef _WIN32 43 | #define WIN32_LEAN_AND_MEAN /* exclude winsock.h because of clash with select() */ 44 | #include /* needed for WinAPI stuff */ 45 | #undef WIN32_LEAN_AND_MEAN 46 | 47 | #define _fullpath(res,path,size) \ 48 | (GetFullPathName ((path), (size), (res), NULL) ? (res) : NULL) 49 | 50 | #define realpath(path,resolved_path) _fullpath(resolved_path, path, MAX_PATH) 51 | 52 | /*********************** statfs *****************************/ 53 | /* fake block size */ 54 | #define FAKED_BLOCK_SIZE 512 55 | 56 | /* linux-compatible values for fs type */ 57 | #define MSDOS_SUPER_MAGIC 0x4d44 58 | #define NTFS_SUPER_MAGIC 0x5346544E 59 | 60 | struct statfs { 61 | long f_type; /* type of filesystem (see below) */ 62 | long f_bsize; /* optimal transfer block size */ 63 | unsigned long f_blocks; /* total data blocks in file system */ 64 | long f_bfree; /* free blocks in fs */ 65 | unsigned long f_bavail; /* free blocks avail to non-superuser */ 66 | long f_files; /* total file nodes in file system */ 67 | long f_ffree; /* free file nodes in fs */ 68 | unsigned long f_fsid; /* file system id */ 69 | unsigned long f_namelen; /* maximum length of filenames */ 70 | long f_spare[6]; /* spare for later */ 71 | }; 72 | 73 | struct utsname { 74 | char sysname[65]; 75 | char machine[65]; 76 | char release[65]; 77 | }; 78 | #endif 79 | 80 | #define ULONG64 unsigned long long 81 | 82 | #define CFGFILE "parcp.cfg" 83 | #define CFGHEAD "[PARCP]" 84 | #define PARCPDIR "PARCPDIR" 85 | 86 | #define TIMER (time(NULL)) 87 | #define TIME_OUT 10 /* main TIMEOUT is set to 10 seconds */ 88 | #define WAIT4CLIENT 100000UL /* 100 ms for giving back the spare CPU cycles */ 89 | #ifndef _WIN32 90 | # define mkdir(a) mkdir(a,0777) /* directory with proper access rights */ 91 | #endif 92 | 93 | #define MAXSTRING 260 94 | #define MAXPATH 260 95 | #define MAXFNAME 100 96 | #define PRINTF_TEMPLATE "%-100s" 97 | #define DIRLINELEN (MAXFNAME+10+1+16+1) 98 | #define DIRBUF_LIN 256 99 | #define BUFFER_LENKB 16 100 | #define KILO 1024UL 101 | #define MAX_DEPTH 8 102 | #define REPEAT_TRANSFER 3 103 | #define REMAINING_TIME_UPDATE_RATE 3 /* how often the remaining time should be updated */ 104 | 105 | #define SLASH '/' 106 | #define SLASH_STR "/" 107 | #define BACKSLASH '\\' 108 | #define DVOJTEKA ':' 109 | #define TOS_DEV "/dev/" 110 | #define Ltos_dev strlen(TOS_DEV) 111 | 112 | #define HASH_CHAR '.' 113 | 114 | #define USAGE "Usage:\n"\ 115 | "PARCP [-s] [-f configfile] [-b batchfile] [-q]\n"\ 116 | "'-s' invokes PARCP Server\n"\ 117 | "'-f configfile' points to PARCP alternate configuration file\n"\ 118 | "'-b batchfile' points to PARCP batch file\n"\ 119 | "'-q' means 'quiet mode' i.e. no messages are written on screen\n" 120 | 121 | /******************************************************************************/ 122 | /* DO NOT change following values - they are important for handshaking */ 123 | #define HI_CLIENT 0x4843 /* 'HC' */ 124 | #define HI_SERVER 0x4853 /* 'HS' */ 125 | #define M_OK 0x0105 126 | #define M_ERR 0xFFFF 127 | 128 | /* following values can be changed without a risk providing you increase PROTOKOL version */ 129 | #define M_QUIT 0x0a00 130 | #define M_LQUIT 0x0a01 131 | #define M_PARS 0x0b00 132 | #define M_PWD 0x0f01 133 | #define M_CD 0x0f02 134 | #define M_MD 0x0f03 135 | #define M_PUT 0x0f04 136 | #define M_PEND 0x0f05 137 | #define M_GET 0x0f06 138 | #define M_DIR 0x0f07 139 | #define M_DEL 0x0f08 140 | #define M_DRV 0x0f09 141 | #define M_OWRITE 0x0f0a 142 | #define M_OSKIP 0x0f0b 143 | #define M_OQUIT 0x0f0c 144 | #define M_REN 0x0f0d 145 | #define M_INT 0x0f0e /* file transfer interrupted */ 146 | #define M_FULL 0x0f0f /* disk full while writting */ 147 | #define M_REPEAT 0x0f10 /* repeat block transfer */ 148 | #define M_UTS 0x0f11 /* send machine info */ 149 | #define M_GETDEL 0x0f12 150 | #define M_OASK 0x0f13 151 | #define M_GETINFO 0x0f14 152 | #define M_GETTIME 0x0f15 153 | #define M_PUTTIME 0x0f16 154 | #define M_DELINFO 0x0f17 155 | #define M_PSTART 0x0f18 156 | #define M_EXCHANGE_FEATURES 0x0f19 157 | #define M_SENDFILESINFO 0x0f20 158 | #define M_EXEC 0x0f21 159 | #define M_EXECNOWAIT 0x0f22 160 | 161 | #define M_UNKNOWN 0xe000 /* unknown command */ 162 | 163 | /* bitove prepinace parametru */ 164 | #define B_CASE 0x0001 /* TRUE = case sensitive matching */ 165 | #define B_HIDDEN 0x0002 /* TRUE = show hidden files on MS-DOS fs */ 166 | #define B_SUBDIR 0x0004 /* TRUE = traverse through folders recursively and sends all files */ 167 | #define B_TIMESTAMP 0x0008 /* TRUE = restore time stamp on copied file */ 168 | #define B_CHECKSUM 0x0010 /* TRUE = use CRC for data safety */ 169 | #define B_ATTRIBS 0x0020 /* TRUE = restore file attributes on copied files */ 170 | #define B_ARCH_MODE 0x0040 /* TRUE = use DOS ATTRIB flag for file backup */ 171 | #define B_PRESERVE 0x0080 /* TRUE = preserve file name upper/lower case on DOS like filesystems */ 172 | #define B_CHECKINFO 0x0100 /* TRUE = show progress info */ 173 | 174 | #define LS_DIRS_ONLY 0x0001 175 | #define LS_FILES_ONLY 0x0002 176 | #define LS_NEGATE_MASK 0x0080 177 | 178 | /******************************************************************************/ 179 | #define FEATURE_LONGLONG (1UL << 0) 180 | #define FEATURE_SENDFILESINFO (1UL << 1) 181 | #define FEATURE_MKDIR_STATUS (1UL << 2) 182 | #define FEATURE_CMD_EXEC (1UL << 3) 183 | #define ALL_FEATURES (FEATURE_LONGLONG | FEATURE_SENDFILESINFO | FEATURE_MKDIR_STATUS | FEATURE_CMD_EXEC) 184 | 185 | /******************************************************************************/ 186 | 187 | char *show_size64(char *buf, ULONG64 size); 188 | void send_long(ULONG64); 189 | ULONG64 receive_long(); 190 | void send_collected_info(void); 191 | void split_filename(const char *pathname, char *path, char *name); 192 | void prepare_fname_for_opendir(const char *pathname, char *path, char *name); 193 | MYBOOL is_absolute_path(const char *path); 194 | MYBOOL has_last_slash(const char *path); 195 | char *add_last_slash(char *path); 196 | char *remove_last_slash(char *path); 197 | 198 | void errexit(const char *, int error_code); 199 | 200 | char *orez_jmeno(const char *jmeno, int delka_jmena); 201 | void view(const char *s, MYBOOL is_dir); 202 | MYBOOL do_client(int, FILE *); 203 | void do_server(void); 204 | void inicializace(void); 205 | void client_server_handshaking(MYBOOL client); 206 | void wait_before_read(void); 207 | 208 | MYBOOL change_dir(const char *p, char *q); 209 | void list_dir(const char *p2, int maska, char *zacatek); 210 | void setridit_list_dir(char *buffer); 211 | int list_drives(char *p); 212 | int delete_files(MYBOOL local, const char *del_mask); 213 | 214 | UWORD read_word(void); 215 | long read_long(void); 216 | void read_block(BYTE *, long); 217 | void receive_string(char *a); 218 | long client_read_block(BYTE *, long); 219 | long server_read_block(BYTE *, long); 220 | long fast_client_read_block(BYTE *, long); 221 | long fast_server_read_block(BYTE *, long); 222 | 223 | void write_word(UWORD x); 224 | void write_long(long x); 225 | void write_block(const BYTE *, long); 226 | void send_string(const char *a); 227 | long client_write_block(const BYTE *, long); 228 | long server_write_block(const BYTE *, long); 229 | long fast_client_write_block(const BYTE *, long); 230 | long fast_server_write_block(const BYTE *, long); 231 | int get_files_info(MYBOOL local, const char *src_mask, MYBOOL arch_mode); 232 | int GetLocalTimeAndSendItOver(void); 233 | int ReceiveDataAndSetLocalTime(void); 234 | //int get_server_files_info(const char *filemask, MYBOOL arch_mode); 235 | 236 | UWORD PackParameters(void); 237 | void send_parameters(void); 238 | 239 | int copy_files(MYBOOL source, const char *p_srcmask, MYBOOL pote_smazat); 240 | MYBOOL stop_waiting(void); 241 | int config_file(const char *soubor, MYBOOL vytvorit); 242 | char *get_cwd(char *path, int maxlen); 243 | MYBOOL file_existuje(char *fname); 244 | char *str_err(int status); 245 | 246 | void parcp_sort(void *base, size_t nel, size_t width, 247 | int (*comp) (const void *, const void *), 248 | void (*swap) (void *, void *)); 249 | 250 | /* SHELL */ 251 | #ifdef SHELL 252 | void do_shell(void); 253 | /* 254 | void shell_open_progress_info(const char *, const char *, long); 255 | void shell_update_progress_info(long); 256 | void shell_close_progress_info(void); 257 | */ 258 | int shell_q_overwrite(const char *); 259 | int shell_q_bugreport(const char *text); 260 | #endif 261 | 262 | #ifdef DEBUG 263 | #define DPRINT(a) debug_print(a) 264 | #define DPRINT1(a,b) debug_print(a,b) 265 | #define DPRINT2(a,b,c) debug_print(a,b,c) 266 | void debug_print(const char *, ... ); 267 | #else 268 | #define DPRINT(a) 269 | #define DPRINT1(a,b) 270 | #define DPRINT2(a,b,c) 271 | #endif 272 | 273 | #ifdef LOWDEBUG 274 | #define LDPRINT(a) debug_print(a) 275 | #define LDPRINT1(a,b) debug_print(a,b) 276 | #define LDPRINT2(a,b,c) debug_print(a,b,c) 277 | void debug_print(const char *, ... ); 278 | #else 279 | #define LDPRINT(a) 280 | #define LDPRINT1(a,b) 281 | #define LDPRINT2(a,b,c) 282 | #endif 283 | 284 | /*******************************************************************************/ 285 | #endif /* _PARCP_H */ 286 | -------------------------------------------------------------------------------- /src/parcp-usb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "element.h" 7 | #include "parcp-usb.h" 8 | 9 | static const int VENDOR_ID = 0x03eb; 10 | static const int PRODUCT_ID = 0x204f; 11 | 12 | #define ERROR_RETRIES 4 13 | 14 | #define MIN(a, b) ( ((a) < (b)) ? (a) : (b) ) 15 | 16 | #include 17 | hid_device *devh = NULL; 18 | 19 | int usb_init(const char *serial) 20 | { 21 | const int MAX_STR = 255; 22 | wchar_t wstr[MAX_STR]; 23 | 24 | if (hid_init()) { 25 | fprintf(stderr, "HID init failed\n"); 26 | return FALSE; 27 | } 28 | 29 | wchar_t *serial_number = NULL; 30 | if (serial != NULL && strlen(serial) > 0) { 31 | int i; 32 | for(i = 0; i <= strlen(serial) && i < MAX_STR; i++) 33 | wstr[i] = btowc(serial[i]); 34 | serial_number = wstr; 35 | } 36 | 37 | devh = hid_open(VENDOR_ID, PRODUCT_ID, serial_number); 38 | if (!devh) { 39 | if (serial_number == NULL) 40 | fprintf(stderr, "HID open failed\n"); 41 | else 42 | fprintf(stderr, "HID open of serial '%ls' failed\n", serial_number); 43 | return FALSE; 44 | } 45 | 46 | int res = hid_get_product_string(devh, wstr, MAX_STR); 47 | if (wcscmp(L"PARCP", wstr)) { 48 | printf("This is not PARCP USB! Product string of the attached device: '%ls'\n", wstr); 49 | return FALSE; 50 | } 51 | 52 | if (serial_number == NULL) { 53 | res = hid_get_serial_number_string(devh, wstr, MAX_STR); 54 | if (res == 0) 55 | printf("PARCP USB Serial Number: %ls\n", wstr); 56 | } 57 | 58 | return TRUE; 59 | } 60 | 61 | void usb_exit() 62 | { 63 | if (devh != NULL) { 64 | hid_close(devh); 65 | } 66 | hid_exit(); 67 | } 68 | 69 | int usb_send(const BYTE *block, int len) 70 | { 71 | BYTE buf[64+1]; 72 | buf[0] = 0; // report number for HIDAPI 73 | memcpy(buf+1, block, len); 74 | int ret = hid_send_feature_report(devh, buf, sizeof(buf)); 75 | if (ret > 0) 76 | ret--; // correct returned number for HIDAPI 77 | return ret; 78 | } 79 | 80 | int usb_receive(BYTE *block, int len) 81 | { 82 | BYTE buf[64+1]; 83 | buf[0] = 0; // report number for HIDAPI 84 | int ret = hid_get_feature_report(devh, buf, sizeof(buf)); 85 | if (ret > 0) { 86 | ret--; // correct returned number for HIDAPI 87 | memcpy(block, buf+1, MIN(ret, len)); 88 | } 89 | return ret; 90 | } 91 | 92 | MYBOOL set_mode(unsigned char output) 93 | { 94 | int bytes_sent = -1; 95 | int error_counter = 0; 96 | unsigned char buf[2]; 97 | #if IODEBUG 98 | fprintf(stderr, "set_mode %s\n", output ? "OUT" : "IN"); 99 | #endif 100 | buf[0] = 0x05; // mode 101 | buf[1] = output; 102 | while(bytes_sent < 2) { 103 | bytes_sent = usb_send(buf, 2); 104 | if (bytes_sent < 2) { 105 | if (error_counter) 106 | fprintf(stderr, "%d. error sending set_mode: %d\n", error_counter, bytes_sent); 107 | #if USBDEBUG 108 | else 109 | fputc('^', stderr); 110 | #endif 111 | if (++error_counter >= ERROR_RETRIES) 112 | return FALSE; 113 | } 114 | } 115 | return TRUE; 116 | } 117 | 118 | MYBOOL set_strobe(unsigned char strobe) 119 | { 120 | int bytes_sent = -1; 121 | int error_counter = 0; 122 | unsigned char buf[2]; 123 | #if IODEBUG 124 | fprintf(stderr, "set_strobe %s\n", strobe ? "HIGH" : "LOW"); 125 | #endif 126 | buf[0] = 0x06; // strobe 127 | buf[1] = strobe; 128 | while(bytes_sent < 2) { 129 | bytes_sent = usb_send(buf, 2); 130 | if (bytes_sent < 2) { 131 | if (error_counter) 132 | fprintf(stderr, "%d. error sending set_strobe: %d\n", error_counter, bytes_sent); 133 | #if USBDEBUG 134 | else 135 | fputc('/', stderr); 136 | #endif 137 | if (++error_counter >= ERROR_RETRIES) 138 | return FALSE; 139 | } 140 | } 141 | return TRUE; 142 | } 143 | 144 | MYBOOL parcpusb_command(unsigned char command) 145 | { 146 | int bytes_sent = -1; 147 | int error_counter = 0; 148 | unsigned char buf[2]; 149 | #if IODEBUG 150 | fprintf(stderr, "parcpusb_command %d\n", command); 151 | #endif 152 | buf[0] = 0x07; // command 153 | buf[1] = command; 154 | while(bytes_sent < 2) { 155 | bytes_sent = usb_send(buf, 2); 156 | if (bytes_sent < 2) { 157 | if (error_counter) 158 | fprintf(stderr, "%d. error sending parcpusb_command: %d\n", error_counter, bytes_sent); 159 | #if USBDEBUG 160 | else 161 | fputc('~', stderr); 162 | #endif 163 | if (++error_counter >= ERROR_RETRIES) 164 | return FALSE; 165 | } 166 | } 167 | return TRUE; 168 | } 169 | 170 | int usb_receive_block(BYTE *data_in, int n) 171 | { 172 | unsigned char buf[USB_BLOCK_SIZE+4+1]; 173 | memset(buf, 0, sizeof(buf)); 174 | int bytes_received = -1; 175 | int error_counter = 0; 176 | while(bytes_received < n) { 177 | bytes_received = usb_receive(buf, sizeof(buf)); 178 | if (bytes_received < n) { 179 | if (error_counter) 180 | fprintf(stderr, "Fatal error receiving block(%d) = %d\n", n, bytes_received); 181 | #if USBDEBUG 182 | else 183 | fputc('&', stderr); 184 | #endif 185 | // must not repeat usb_receive_block or the client-server sync breaks 186 | // if (++error_counter >= ERROR_RETRIES) 187 | return -1; 188 | } 189 | } 190 | memcpy(data_in, buf, n); 191 | return MIN(bytes_received, n); 192 | } 193 | 194 | int usb_transmit_block(const BYTE *data_out, int n) 195 | { 196 | int bytes_sent = -1; 197 | int error_counter = 0; 198 | while(bytes_sent < n) { 199 | bytes_sent = usb_send(data_out, n); 200 | if (bytes_sent < n) { 201 | if (error_counter) 202 | fprintf(stderr, "%d. error sending block(%d) = %d\n", error_counter, n, bytes_sent); 203 | #if USBDEBUG 204 | else 205 | fputc('|', stderr); 206 | #endif 207 | if (++error_counter >= ERROR_RETRIES) 208 | return -1; 209 | } 210 | } 211 | return MIN(bytes_sent, n); 212 | } 213 | 214 | int get_busy() 215 | { 216 | unsigned char buf[6]; 217 | // requires new firmware and two roundtrips just to get the BUSY status 218 | parcpusb_command(0); // any command sets the global_action in firmware to zero 219 | usb_receive_block(buf, sizeof(buf)); // read with global_action == 0 returns information packet 220 | // PROTOCOL_VERSION in buf[0] 221 | // FIRMWARE_VERSION in buf[1],buf[2] 222 | MYBOOL busy = buf[3]; 223 | #if IODEBUG 224 | fprintf(stderr, "get_busy OK: %s\n", busy ? "HIGH" : "LOW"); 225 | #endif 226 | if (buf[5]) 227 | fprintf(stderr, "!! error in adapter - write offset mismatch #%d\n", buf[5]); 228 | return busy; 229 | } 230 | 231 | int usb_set_client_read_size(long n) 232 | { 233 | unsigned char buffer[4]; 234 | buffer[0] = 0x01; // 0x01 = client read 235 | buffer[1] = n >> 16; 236 | buffer[2] = n >> 8; 237 | buffer[3] = n; 238 | int sent = usb_transmit_block(buffer, 4); 239 | return (sent == 4) ? 0 : -1; 240 | } 241 | 242 | int usb_set_server_read_size(long n) 243 | { 244 | unsigned char buffer[4]; 245 | buffer[0] = 0x02; // 0x02 = server read 246 | buffer[1] = n >> 16; 247 | buffer[2] = n >> 8; 248 | buffer[3] = n; 249 | int sent = usb_transmit_block(buffer, 4); 250 | return (sent == 4) ? 0 : -1; 251 | } 252 | 253 | int usb_set_client_write_size(long n, const BYTE *block) 254 | { 255 | unsigned char buffer[USB_BLOCK_SIZE+4]; 256 | buffer[0] = 0x03; // 0x03 = client write 257 | buffer[1] = n >> 16; 258 | buffer[2] = n >> 8; 259 | buffer[3] = n; 260 | int to_send = MIN(n, USB_BLOCK_SIZE); 261 | memcpy(buffer + 4, block, to_send); 262 | #if IODEBUG 263 | fprintf(stderr, "usb_set_client_write_size(%ld): %d %d %d...\n", n, block[0], block[1], block[2]); 264 | #endif 265 | int sent = usb_transmit_block(buffer, to_send+4); 266 | return (sent == to_send+4) ? 0 : -1; 267 | } 268 | 269 | int usb_set_server_write_size(long n, const BYTE *block) 270 | { 271 | unsigned char buffer[USB_BLOCK_SIZE+4]; 272 | buffer[0] = 0x04; // 0x04 = server write 273 | buffer[1] = n >> 16; 274 | buffer[2] = n >> 8; 275 | buffer[3] = n; 276 | int to_send = MIN(n, USB_BLOCK_SIZE); 277 | memcpy(buffer + 4, block, to_send); 278 | int sent = usb_transmit_block(buffer, to_send+4); 279 | return (sent == to_send+4) ? 0 : -1; 280 | } 281 | 282 | int usb_read_block(BYTE *block, long offset, int n) 283 | { 284 | unsigned char buffer[USB_BLOCK_SIZE+4]; 285 | assert(n <= USB_BLOCK_SIZE); 286 | memset(buffer, 0, sizeof(buffer)); 287 | int received = usb_receive_block(buffer, n+4); 288 | int data_received = buffer[0]; 289 | MYBOOL all_data_received = (received >= n+4 && (data_received == n || data_received-1 == n)); // -1 => correction for always even transfer size 290 | if (!all_data_received) 291 | fprintf(stderr, "!! read_block(%ld, %d) read only %d bytes\n", offset, n, data_received); 292 | #if DEBUG 293 | else 294 | fprintf(stderr, "oo read_block(%ld, %d) OK\n", offset, n); 295 | #endif 296 | long bufoff = (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; 297 | if (bufoff != offset) 298 | fprintf(stderr, "!! read_block(%ld, %d) received offset %ld does not match\n", offset, n, bufoff); 299 | #if IODEBUG 300 | fprintf(stderr, "usb_read_block(%ld, %d) = [$%02x $%02x $%02x $%02x $%02x $%02x]\n", offset, n, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); 301 | #endif 302 | memcpy(block + offset, buffer+4, n); 303 | return all_data_received ? 0 : -1; 304 | } 305 | 306 | int usb_write_block(const BYTE *block, long offset, int n) 307 | { 308 | unsigned char buffer[USB_BLOCK_SIZE+4]; 309 | buffer[0] = 0x08; // data transmit 310 | buffer[1] = offset >> 16; 311 | buffer[2] = offset >> 8; 312 | buffer[3] = offset; 313 | memcpy(buffer+4, block + offset, n); 314 | #if IODEBUG 315 | fprintf(stderr, "usb_write_block(%ld, %d)\n", offset, n); 316 | #endif 317 | int sent = usb_transmit_block(buffer, n+4); 318 | return (sent == n+4) ? 0 : -1; 319 | } 320 | 321 | #if 0 322 | int main() 323 | { 324 | BYTE buf[USB_BLOCK_SIZE+2]; 325 | 326 | int strobe = 0; 327 | 328 | if (usb_init() == 0) { fprintf(stderr, "USB init failed\n"); return 1; } 329 | 330 | set_mode(TRUE); 331 | 332 | int i; 333 | for(i=0; i<5; i++) { 334 | #if 1 335 | printf("STROBE %s\n", strobe ? "HIGH" : "LOW"); 336 | set_strobe(strobe); 337 | set_mode(strobe); 338 | strobe = !strobe; 339 | printf("BUSY %s\n", get_busy() ? "HIGH" : "LOW"); 340 | #else 341 | buf[0] = buf[1] = buf[2] = buf[3] = 0; 342 | usb_client_read_block(buf, 2, TRUE); 343 | printf("[0]=%d, [1]=%d, [2]=%d, [3]=%d\n", buf[0], buf[1], buf[2], buf[3]); 344 | #endif 345 | sleep(1); 346 | } 347 | 348 | usb_exit(); 349 | return 0; 350 | } 351 | #endif 352 | -------------------------------------------------------------------------------- /src/viewer.c: -------------------------------------------------------------------------------- 1 | /* PARCP File Viewer 2 | * written by Petr Stehlik 3 | * (c) 1994 - 2016 4 | */ 5 | #include "element.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #define REVERSE_INFOLINE 11 | 12 | #define ESC 27 13 | #define KEY_BACKS 0x8 14 | #define MAXCHAR 160 15 | #define POCETRADKU (LINES-1) 16 | #define LASTLINE (POCETRADKU-1) 17 | #define DELKASTRANY POCETRADKU 18 | 19 | long aktradek, /* number of the actual line */ 20 | ActPos, /* number of the first displayed line */ 21 | LastPagePos, /* position of the first undisplayable line on the first row */ 22 | EndPos, 23 | poslstrana, 24 | pocetradku, /* number of lines of the whole document */ 25 | pocetstran, /* number of pages of the whole document */ 26 | pgbuf; /* offset of the text in the buffer */ 27 | 28 | char Sestava[512], /* buffer for one line */ 29 | String[256]; /* space for last searched string */ 30 | char view_fname[260]; 31 | 32 | int StartCh, /* horizontal offset */ 33 | HWscroll, /* insert&delete features capability */ 34 | cursor_visibility, 35 | tab_size=8; 36 | 37 | FILE *fdd; 38 | 39 | WINDOW *okno, *headline; 40 | PANEL *pokno, *phead; 41 | 42 | extern BYTE *block_buffer; 43 | extern long buffer_len; 44 | 45 | #define Redraw showpage(aktradek) 46 | 47 | BYTE soubor(pos) 48 | long pos; 49 | { 50 | size_t newpage, bufcount; 51 | 52 | if((newpage = (pos / buffer_len)) != pgbuf) { 53 | pgbuf = newpage; 54 | fseek(fdd, pgbuf * buffer_len, SEEK_SET); 55 | bufcount = fread(block_buffer, 1, buffer_len, fdd); 56 | memset(block_buffer+bufcount, '\n', buffer_len-bufcount); 57 | } 58 | return ( block_buffer[pos % buffer_len] ); 59 | } 60 | 61 | long findprevnl(pos) 62 | long pos; 63 | { 64 | if (pos) pos--; /* move to the end of the previous line */ 65 | while(pos > 0 && soubor(pos - 1) != '\n') 66 | --pos; 67 | return pos; 68 | } 69 | 70 | long findnextnl(pos) 71 | long pos; 72 | { 73 | long i = pos; 74 | while(i < EndPos && soubor(i) != '\n') 75 | i++; 76 | if (i < EndPos) /* if we are somewhere in the middle of the text */ 77 | return i + 1; /* then return the next position after '\n' */ 78 | else 79 | return pos; /* otherwise return the same position we started from */ 80 | } 81 | 82 | void spocitej() 83 | { 84 | long pos; 85 | int i; 86 | 87 | fseek(fdd,0L,SEEK_END); 88 | pos = EndPos = ftell(fdd); 89 | pocetradku = 1; 90 | while((pos = findprevnl(pos)) > 0) 91 | pocetradku++; 92 | pocetstran = pocetradku / DELKASTRANY; 93 | if (pocetradku % DELKASTRANY) 94 | pocetstran++; 95 | if ((poslstrana = pocetradku - POCETRADKU) < 0) 96 | poslstrana = 0; 97 | pos = EndPos; 98 | for(i = 0; i < POCETRADKU; i++) 99 | if ((pos = findprevnl(pos)) == 0) 100 | break; 101 | LastPagePos = pos; 102 | } 103 | 104 | void ctiradek(pos) 105 | long pos; 106 | /* Limitations: 107 | 1) last line must contain '\n' 108 | 2) each line must be shorter than 512 characters 109 | */ 110 | { 111 | int i, j; 112 | BYTE a; 113 | 114 | memset(Sestava, ' ', COLS); 115 | for(i = 0; i < StartCh; i++) { 116 | if ((a = soubor(pos++)) == '\n') { 117 | strcpy(Sestava,""); 118 | return; 119 | } 120 | } 121 | for(i = 0; i < COLS; ) { 122 | if ((a = soubor(pos++)) == '\n') 123 | break; 124 | if (a == '\t') { 125 | a = ' '; 126 | for(j=(i+1)%tab_size; j%tab_size; j++) 127 | Sestava[i++] = a; 128 | } 129 | else if (a < ' ') 130 | a = ' '; 131 | Sestava[i++] = a; 132 | } 133 | Sestava[COLS-1] = '\0'; 134 | } 135 | 136 | void showpage(radek) 137 | long radek; 138 | { 139 | long pozice, i; 140 | 141 | if (radek == aktradek-1) { 142 | if (radek >= 0) { 143 | aktradek = radek; 144 | ActPos = findprevnl(ActPos); 145 | ctiradek(ActPos); 146 | wscrl(okno,-1); 147 | mvwaddstr(okno, 0, 0, Sestava); 148 | } 149 | } 150 | else if (radek == aktradek+1) { 151 | if (radek <= poslstrana) { 152 | aktradek = radek; 153 | ActPos = findnextnl(ActPos); 154 | pozice = ActPos; 155 | for(i = 0; i < LASTLINE; i++) 156 | pozice = findnextnl(pozice); 157 | ctiradek(pozice); 158 | scroll(okno); 159 | mvwaddstr(okno, LASTLINE, 0, Sestava); 160 | } 161 | } 162 | else { 163 | if (radek <= 0) { 164 | aktradek = radek = 0; 165 | ActPos = 0; 166 | } 167 | else if (radek >= poslstrana) { 168 | aktradek = radek = poslstrana; 169 | ActPos = LastPagePos; 170 | } 171 | if (aktradek < radek) 172 | for(i = radek - aktradek; i > 0; --i) 173 | ActPos = findnextnl(ActPos); 174 | if (aktradek > radek) 175 | for(i = aktradek - radek; i > 0; --i) 176 | ActPos = findprevnl(ActPos); 177 | aktradek = radek; 178 | pozice = ActPos; 179 | for (i = 0; i <= LASTLINE; i++) { 180 | ctiradek(pozice); 181 | pozice = findnextnl(pozice); 182 | mvwaddstr(okno, i, 0, Sestava); 183 | } 184 | } 185 | 186 | #ifdef REVERSE_INFOLINE 187 | wattron(headline, A_REVERSE); 188 | #endif 189 | mvwprintw(headline,0,0,"'%s' Line: %d Page: %d/%d Press F1 for help ",view_fname,aktradek+1,(aktradek+1)/DELKASTRANY+1,pocetstran); 190 | #ifdef REVERSE_INFOLINE 191 | wattroff(headline, A_REVERSE); 192 | #endif 193 | wclrtoeol(headline); 194 | update_panels(); 195 | } 196 | 197 | void tisk_inverz(const char *text) 198 | { 199 | wattron(headline,A_REVERSE); 200 | mvwaddstr(headline,0,0,text); 201 | wattroff(headline,A_REVERSE); 202 | wclrtoeol(headline); 203 | } 204 | 205 | int Nacti_cislo() 206 | { 207 | int c, cislo = 0; 208 | 209 | curs_set(cursor_visibility); 210 | for(;;) { 211 | update_panels(); 212 | doupdate(); 213 | c = wgetch(headline); 214 | if (c == '\n') 215 | break; 216 | if (c >= '0' && c <= '9') { 217 | waddch(headline, c); 218 | cislo = cislo*10 + (c - '0'); 219 | } 220 | } 221 | curs_set(0); 222 | return cislo; 223 | } 224 | 225 | void ReadString(char *StringName) 226 | { 227 | curs_set(cursor_visibility); 228 | getstr(StringName); 229 | curs_set(0); 230 | } 231 | 232 | long FindDString() 233 | { 234 | long pos, kon, radek; 235 | int j, Find, delka; 236 | 237 | delka = strlen((char *)String); 238 | for(radek = aktradek+1, kon = findnextnl(ActPos); radek < pocetradku; radek++) { 239 | pos = kon; 240 | kon = findnextnl(pos); 241 | while(pos < kon) 242 | if (soubor(pos++) == String[0]) { 243 | Find = TRUE; 244 | for (j = 1; j < delka; j++) 245 | if (soubor(pos++) != String[j]) { 246 | Find = FALSE; 247 | break; 248 | } 249 | if (Find) 250 | return radek; 251 | } 252 | } 253 | return -1; 254 | } 255 | 256 | void FindDownString(Repeat) 257 | int Repeat; 258 | { 259 | long radek; 260 | 261 | if (! Repeat) { 262 | tisk_inverz(" Search string: "); 263 | ReadString(String); 264 | } 265 | tisk_inverz(" Searching... "); 266 | if ((radek = FindDString()) >= 0) 267 | showpage(radek); 268 | else { 269 | tisk_inverz(" String not found. "); 270 | beep(); 271 | } 272 | } 273 | 274 | void Help() 275 | { 276 | werase(okno); 277 | waddstr(okno, "ParShell Internal Viewer (c) Petr Stehlik 1994-2016\n\n"); 278 | waddstr(okno, "Navigation:\n"); 279 | waddstr(okno, "-----------\n"); 280 | waddstr(okno, "Cursor keys, PageUp/Down, Home/End\n"); 281 | waddstr(okno, "F1 .... this help\n"); 282 | waddstr(okno, "F2 .... first page\n"); 283 | waddstr(okno, "F3 .... last page\n"); 284 | waddstr(okno, "F4 .... direct jump to a page\n"); 285 | waddstr(okno, "F7 .... find a string\n"); 286 | waddstr(okno, "F5 .... repeat finding\n"); 287 | waddstr(okno, "F8 .... change tabstop\n"); 288 | waddstr(okno, "F9 .... redraw screen\n"); 289 | waddstr(okno, "F10 ... exit viewer\n"); 290 | waddstr(okno, "\npress Return"); 291 | update_panels(); 292 | doupdate(); 293 | wgetch(okno); 294 | Redraw; 295 | } 296 | 297 | void KeyLoop() 298 | { 299 | int Done = FALSE; 300 | long nastranu; 301 | 302 | while (! Done) { 303 | update_panels(); 304 | doupdate(); 305 | switch(wgetch(okno)) { 306 | case KEY_F(2): 307 | #ifndef ATARI 308 | case '2': 309 | #endif 310 | showpage(0); break; 311 | 312 | case KEY_F(3): 313 | #ifndef ATARI 314 | case '3': 315 | #endif 316 | showpage(poslstrana); break; 317 | 318 | case KEY_UP: 319 | showpage(aktradek-1); break; 320 | 321 | case KEY_DOWN: 322 | showpage(aktradek+1); break; 323 | 324 | #ifdef ATARI 325 | case '8': 326 | #endif 327 | case KEY_PPAGE: 328 | showpage(aktradek-POCETRADKU); break; 329 | 330 | #ifdef ATARI 331 | case '2': 332 | #endif 333 | case KEY_NPAGE: 334 | showpage(aktradek+POCETRADKU); break; 335 | 336 | case KEY_LEFT: 337 | if (StartCh > 0) 338 | --StartCh; 339 | Redraw; 340 | break; 341 | 342 | case KEY_RIGHT: 343 | if (StartCh < MAXCHAR-COLS) 344 | StartCh++; 345 | Redraw; 346 | break; 347 | 348 | case KEY_HOME: 349 | StartCh = 0; 350 | Redraw; 351 | break; 352 | 353 | case KEY_END: 354 | StartCh = MAXCHAR-COLS; 355 | Redraw; 356 | break; 357 | 358 | case KEY_F(8): 359 | #ifndef ATARI 360 | case '8': 361 | #endif 362 | if ( (tab_size <<= 1) > 8) 363 | tab_size = 2; 364 | Redraw; 365 | break; 366 | 367 | case KEY_F(9): 368 | #ifndef ATARI 369 | case '9': 370 | #endif 371 | Redraw; 372 | break; 373 | 374 | case KEY_F(4): 375 | #ifndef ATARI 376 | case '4': 377 | #endif 378 | tisk_inverz(" Go to page: "); 379 | nastranu = (Nacti_cislo() - 1) * DELKASTRANY; 380 | showpage(nastranu); 381 | break; 382 | 383 | case KEY_F(1): 384 | #ifndef ATARI 385 | case '1': 386 | #endif 387 | Help(); 388 | break; 389 | 390 | case ESC: 391 | case KEY_F(10): 392 | #ifndef ATARI 393 | case '0': 394 | #endif 395 | Done = TRUE; 396 | break; 397 | 398 | case KEY_F(7): 399 | #ifndef ATARI 400 | case '7': 401 | #endif 402 | FindDownString(FALSE); break; 403 | 404 | case KEY_F(5): 405 | #ifndef ATARI 406 | case '5': 407 | #endif 408 | FindDownString(TRUE); break; 409 | } 410 | } 411 | } 412 | 413 | void viewer(char *fname) 414 | { 415 | strcpy(view_fname, fname); 416 | if ((fdd = fopen(view_fname, "r")) == NULL) 417 | return; 418 | pgbuf = -1; 419 | headline = newwin(1,COLS,0,0); 420 | phead = new_panel(headline); 421 | okno = newwin(POCETRADKU,COLS,1,0); 422 | pokno = new_panel(okno); 423 | keypad(okno, TRUE); 424 | scrollok(okno,TRUE); 425 | wclear(okno); 426 | spocitej(); 427 | StartCh = 0; 428 | showpage(0); 429 | KeyLoop(); 430 | fclose(fdd); fdd = NULL; 431 | 432 | del_panel(pokno); 433 | delwin(okno); 434 | 435 | del_panel(phead); 436 | delwin(headline); 437 | } 438 | -------------------------------------------------------------------------------- /src/menu.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | #include "menu.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #define WINWIDTH (TITWIDTH+2) /* width of inner window */ 8 | #define BORWIDTH (WINWIDTH+2) /* window border width */ 9 | 10 | #define MENU_MAXCOLUMNS sirka /* defined in shell.h */ 11 | #define MENU_MAXROWS 24 /*vyska*/ /* defined in shell.h */ 12 | 13 | WINDOW *st_text; 14 | PANEL *pst_text; 15 | MYBOOL end_menu; 16 | 17 | TMENU *new_item(const char *title, const char *stat_text, int command, int parent) 18 | { 19 | TMENU *pmenu; 20 | pmenu = (TMENU *) malloc(sizeof(TMENU)); 21 | 22 | if (title) { 23 | strncpy(pmenu->title, title, TITWIDTH); 24 | pmenu->title[TITWIDTH] = '\0'; 25 | pmenu->flag = MENU_PASSED; 26 | } else { 27 | pmenu->flag = MENU_DISABLED; 28 | } 29 | 30 | if (stat_text) 31 | strcpy(pmenu->stat_text, stat_text); 32 | else 33 | *pmenu->stat_text = 0; 34 | 35 | pmenu->command = command; 36 | pmenu->parent = parent; 37 | return pmenu; 38 | } 39 | 40 | void free_item(TMENU *item) 41 | { 42 | free(item); 43 | } 44 | 45 | TMENU *new_menu(TMENU ** itemlist) 46 | { 47 | TMENU *item, *next; 48 | int i, j, rodic = -2; 49 | 50 | for (i = 0; (item = itemlist[i]) != NULL; i++) { 51 | item->wnew = NULL; 52 | if ((j = item->parent) >= 0) { 53 | if (j == rodic) 54 | continue; 55 | rodic = j; 56 | itemlist[rodic]->wnew = item; 57 | itemlist[rodic]->flag |= MENU_SUBTREE; 58 | } 59 | } 60 | next = NULL; 61 | rodic = -2; 62 | while (i--) { /* backward */ 63 | item = itemlist[i]; 64 | j = item->parent; /* parent number */ 65 | if (j != rodic) { /* differs from the last one? */ 66 | item->next = NULL; /* end of the new submenu */ 67 | rodic = j; /* remember the parent of this submenu */ 68 | } else 69 | item->next = next; 70 | next = item; 71 | } 72 | 73 | return itemlist[0]; 74 | } 75 | 76 | void show_items(WINDOW * win, TMENU * smenu, int poloha) 77 | { 78 | TMENU *act; 79 | char tmpspc[TITWIDTH + 3]; 80 | int i; 81 | 82 | act = smenu; 83 | i = 0; 84 | while (act != NULL) { 85 | if (poloha != i) 86 | wattron(win, A_REVERSE); 87 | else 88 | wattroff(win, A_REVERSE); 89 | 90 | if (!(act->flag & MENU_DISABLED)) { 91 | MYBOOL odymil = FALSE; 92 | 93 | memset(tmpspc, ' ', WINWIDTH); 94 | if (!(act->flag & MENU_PASSED)) { 95 | if (has_dim) { 96 | wattron(win, A_DIM); 97 | odymil = TRUE; 98 | } else 99 | memset(tmpspc, '-', WINWIDTH); 100 | } 101 | 102 | memcpy(tmpspc + 1, act->title, strlen(act->title)); 103 | 104 | if (act->flag & MENU_SUBTREE) 105 | tmpspc[TITWIDTH + 1] = '>'; 106 | 107 | tmpspc[WINWIDTH] = 0; 108 | mvwaddstr(win, i, 0, tmpspc); 109 | 110 | if (act->flag & MENU_CHECKED) 111 | mvwaddch(win, i, 0, '+'); 112 | 113 | if (odymil) 114 | wattroff(win, A_DIM); 115 | } else { 116 | wmove(win, i, 0); 117 | whline(win, ACS_HLINE, WINWIDTH); 118 | } 119 | 120 | act = act->next; 121 | i++; 122 | } 123 | } 124 | 125 | TMENU * find_prev_item(TMENU *first, TMENU *act) 126 | { 127 | TMENU *item = first; 128 | while(item != NULL && item->next != act) 129 | item = item->next; 130 | 131 | return item; 132 | } 133 | 134 | int find_menu_prev(TMENU * first, int p, int pocet) 135 | { 136 | int i, j; 137 | TMENU *act; 138 | 139 | i = p; 140 | do { 141 | if (i == 0) 142 | i = pocet; 143 | i--; 144 | act = first; 145 | for (j = 0; j < i; j++) 146 | act = act->next; 147 | } while (!(act->flag & MENU_PASSED)); 148 | return i; 149 | } 150 | 151 | int find_menu_next(TMENU * first, int p, int pocet) 152 | { 153 | int i, j; 154 | TMENU *act; 155 | 156 | i = p; 157 | do { 158 | i++; 159 | if (i >= pocet) 160 | i = 0; 161 | act = first; 162 | for (j = 0; j < i; j++) 163 | act = act->next; 164 | } while (!(act->flag & MENU_PASSED)); 165 | return i; 166 | } 167 | 168 | void toggle_command(TMENU * first, int cm, int set) 169 | { 170 | TMENU *act; 171 | 172 | act = first; 173 | while (act != NULL) { 174 | if (act->command == cm && !(act->flag & MENU_DISABLED)) { 175 | if (set) 176 | act->flag |= MENU_PASSED; 177 | else 178 | act->flag &= ~MENU_PASSED; 179 | break; 180 | } else if (act->flag & MENU_SUBTREE) 181 | toggle_command(act->wnew, cm, set); 182 | act = act->next; 183 | } 184 | } 185 | 186 | void toggle_icheck(TMENU * first, int cm, int set) 187 | { 188 | TMENU *act; 189 | 190 | act = first; 191 | while (act != NULL) { 192 | if (act->command == cm) { 193 | act->flag |= MENU_CHECKABLE; 194 | if (set) 195 | act->flag |= MENU_CHECKED; 196 | else 197 | act->flag &= ~MENU_CHECKED; 198 | break; 199 | } else if (act->flag & MENU_SUBTREE) 200 | toggle_icheck(act->wnew, cm, set); 201 | act = act->next; 202 | } 203 | } 204 | 205 | void click_radio(TMENU * first, int cm) 206 | { 207 | TMENU *act; 208 | 209 | act = first; 210 | while (act != NULL) { 211 | if (act->command == cm) { 212 | TMENU *item; 213 | act->flag |= MENU_RADIO; 214 | // nastav vsem predchazejicim itemum flag RADIO 215 | item = act; 216 | while((item = find_prev_item(first, item))) { 217 | if (item->flag & (MENU_SUBTREE | MENU_DISABLED)) 218 | break; 219 | else { 220 | item->flag |= MENU_RADIO; 221 | item->flag &= ~MENU_CHECKED; 222 | } 223 | } 224 | // nastav vsem nasledujicim itemum flag RADIO 225 | item = act; 226 | while((item = item->next)) { 227 | if (item->flag & (MENU_SUBTREE | MENU_DISABLED)) 228 | break; 229 | else { 230 | item->flag |= MENU_RADIO; 231 | item->flag &= ~MENU_CHECKED; 232 | } 233 | } 234 | 235 | // nastav samotny button 236 | act->flag |= MENU_CHECKED; 237 | break; 238 | } else if (act->flag & MENU_SUBTREE) 239 | click_radio(act->wnew, cm); 240 | act = act->next; 241 | } 242 | } 243 | 244 | MYBOOL is_checked(TMENU * first, int cm) 245 | { 246 | TMENU *act; 247 | int vysledek = -1; 248 | 249 | act = first; 250 | while (act != NULL && vysledek == -1) { 251 | if (act->command == cm) { 252 | vysledek = (act->flag & MENU_CHECKED) ? TRUE : FALSE; /* found! */ 253 | break; 254 | } else if (act->flag & MENU_SUBTREE) 255 | vysledek = is_checked(act->wnew, cm); 256 | act = act->next; 257 | } 258 | return vysledek; 259 | } 260 | 261 | void set_radio(TMENU * imenu, TMENU *act) 262 | { 263 | if (!(act->flag & MENU_CHECKED)) { 264 | TMENU *item = act; 265 | /* unselect all previous items */ 266 | while((item = find_prev_item(imenu, item))) { 267 | if (item->flag & MENU_RADIO) 268 | item->flag &= ~MENU_CHECKED; 269 | else 270 | break; 271 | } 272 | /* unselect all following items */ 273 | item = act; 274 | while((item = item->next)) { 275 | if (item->flag & MENU_RADIO) 276 | item->flag &= ~MENU_CHECKED; 277 | else 278 | break; 279 | } 280 | /* select the current one */ 281 | act->flag |= MENU_CHECKED; 282 | } 283 | } 284 | 285 | int show_menu(TMENU * imenu, int cx, int cy) 286 | { 287 | int i, sy, j; 288 | WINDOW *wwborder, *wwmenu; 289 | PANEL *pwwborder; 290 | int klavesa = 0; 291 | int comm; 292 | TMENU *act; 293 | 294 | sy = 0; 295 | act = imenu; 296 | end_menu = 0; 297 | while (act != NULL) { 298 | act = act->next; 299 | sy++; 300 | } 301 | 302 | if ((cy + sy) > MENU_MAXROWS - 2) { 303 | cy = MENU_MAXROWS - 2 - sy; 304 | if (cy < 0) 305 | return 0; /* do not open this menu */ 306 | } 307 | if ((cx + BORWIDTH) > MENU_MAXCOLUMNS - 1) { 308 | cx = MENU_MAXCOLUMNS - 1 - BORWIDTH; 309 | if (cx < 0) 310 | return 0; /* do not open this menu */ 311 | } 312 | 313 | wwborder = newwin(sy + 2, BORWIDTH, cy, cx); 314 | wattron(wwborder, A_REVERSE); 315 | box(wwborder, ACS_VLINE, ACS_HLINE); 316 | 317 | #if NAPOVEDA 318 | st_text = newwin(1, 79, 0, 0); 319 | pst_text = new_panel(st_text); 320 | wattron(st_text, A_REVERSE); 321 | wclear(st_text); 322 | #endif 323 | 324 | wwmenu = derwin(wwborder, sy, WINWIDTH, 1, 1); 325 | wattron(wwmenu, A_REVERSE); 326 | klavesa = 0; 327 | comm = 0; 328 | keypad(wwmenu, TRUE); 329 | // refresh(); 330 | pwwborder = new_panel(wwborder); 331 | update_panels(); 332 | i = find_menu_next(imenu, sy, sy); 333 | 334 | while ((klavesa != KEY_LEFT) && (end_menu == 0)) { 335 | MEVENT mevent; 336 | act = imenu; 337 | for (j = 0; j < i; j++) 338 | act = act->next; 339 | show_items(wwmenu, imenu, i); 340 | update_panels(); 341 | doupdate(); 342 | klavesa = wgetch(wwmenu); 343 | switch (klavesa) { 344 | case KEY_MOUSE: 345 | if (getmouse(&mevent) != OK) break; 346 | if (! (mevent.bstate & BUTTON1_CLICKED)) break; 347 | if (mevent.x < cx || mevent.x > cx + WINWIDTH) { 348 | klavesa = KEY_LEFT; 349 | break; 350 | } 351 | if (mevent.y <= cy || mevent.y > cy + sy) break; 352 | { 353 | int i_ = mevent.y - cy - 1; /* this is the selected item */ 354 | /* find menu item */ 355 | TMENU *act_ = imenu; 356 | for(j = 0; j < i_; j++) 357 | act_ = act_->next; 358 | if (act_->title == NULL) break; // menu separator 359 | /* select an item */ 360 | i = i_; 361 | act = act_; 362 | show_items(wwmenu, imenu, i); 363 | wrefresh(wwmenu); 364 | } 365 | /* fall through = mouse click simulates the Enter key */ 366 | case '\r': 367 | case '\n': 368 | if (act->flag & MENU_SUBTREE) 369 | comm = show_menu(act->wnew, cx + BORWIDTH, cy + i); 370 | else if (act->flag & MENU_RADIO) { 371 | set_radio(imenu, act); 372 | } 373 | else if (act->flag & MENU_CHECKABLE) 374 | act->flag ^= MENU_CHECKED; 375 | else { 376 | comm = act->command; 377 | end_menu = 1; 378 | } 379 | break; 380 | 381 | case 32: 382 | if (act->flag & MENU_RADIO) { 383 | set_radio(imenu, act); 384 | } 385 | else if (act->flag & MENU_CHECKABLE) 386 | act->flag ^= MENU_CHECKED; 387 | break; 388 | 389 | case KEY_F(9): 390 | case KEY_F(10): 391 | #ifndef ATARI 392 | case '9': 393 | case '0': 394 | #endif 395 | case KEY_UNDO: 396 | case 27: /* Escape */ 397 | comm = 0; 398 | end_menu = 1; 399 | break; 400 | case KEY_UP: 401 | i = find_menu_prev(imenu, i, sy); 402 | break; 403 | case KEY_DOWN: 404 | i = find_menu_next(imenu, i, sy); 405 | break; 406 | case KEY_RIGHT: 407 | if (act->flag & MENU_SUBTREE) 408 | comm = show_menu(act->wnew, cx + BORWIDTH, cy + i); 409 | break; 410 | } 411 | } 412 | 413 | delwin(wwmenu); 414 | #if NAPOVEDA 415 | del_panel(pst_text); 416 | delwin(st_text); 417 | #endif 418 | del_panel(pwwborder); 419 | delwin(wwborder); 420 | 421 | update_panels(); 422 | return comm; 423 | } 424 | -------------------------------------------------------------------------------- /src/box.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PARallel CoPy - written for transferring large files between any two machines 3 | * with parallel ports. 4 | * 5 | * Petr Stehlik (c) 1996-2023 6 | * 7 | */ 8 | 9 | #include "element.h" 10 | #include "shell.h" 11 | #include "box.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define BOX_MAX_WIDTH 70 20 | 21 | int min(int a, int b) 22 | { 23 | return a < b ? a : b; 24 | } 25 | 26 | int max(int a, int b) 27 | { 28 | return a > b ? a : b; 29 | } 30 | 31 | /* 32 | Breaks long string to several strings of max_width, divided by '\0' 33 | and returns the number of lines you need to display the strings. 34 | */ 35 | int FormatTextToBox(char *text, int max_width) 36 | { 37 | int lines=1; 38 | int delka = strlen(text); 39 | char *p; /* pointer to begin of actual line */ 40 | char *q; /* pointer to start of next search */ 41 | char *rozdel; /* pointer to last place suitable for breaking the line */ 42 | char *konec; /* pointer to end of the text */ 43 | q = p = text; 44 | rozdel = text-1;/* pointer to last line break */ 45 | konec = text + delka; 46 | 47 | if (delka > max_width) { 48 | while(q < konec) { /* q was last place suitable for breaking */ 49 | char *r = strpbrk(q, " \t/\\\n"); /* find next suitable place for the break */ 50 | if (r == NULL) 51 | r = konec; /* if there's no place then point to the end */ 52 | 53 | if ((r-p) < max_width && *r != '\n') { /* '\n' is always used for breaking */ 54 | rozdel = r; /* remember new place suitable for breaking */ 55 | q++; 56 | continue; /* search again */ 57 | } 58 | 59 | if ((r-p) > max_width) { /* too long line already? */ 60 | if (p > rozdel) /* bad luck - no place for the delimiter. Let's do it the strong way */ 61 | rozdel = p + max_width; /* we loose one character */ 62 | } 63 | else 64 | rozdel = r; /* break in this place */ 65 | 66 | *rozdel = '\0'; /* BREAK */ 67 | p = q = rozdel+1; /* next line begins here */ 68 | lines++; /* increment line counter */ 69 | } 70 | } 71 | return lines; /* return line counter */ 72 | } 73 | 74 | /* 75 | Displays a dialog box and allows user to select from one to three buttons. 76 | Selection can be done by arrows or TAB key or even by the first char of 77 | the button label. If there's the "Cancel" button it can be selected by 78 | pressing the ESC key. 79 | */ 80 | int myMessageBox(const char *text, int type) 81 | { 82 | WINDOW *pwinalert; 83 | PANEL *ppanalert; 84 | int wx, wy, ww, wh, radku, butposy, numbut, key, sumlen, spclen, active, i, chosen; 85 | char *button[3]; 86 | int butlen[3], butpos[3], hotkey[3], ret[3]; 87 | char *kopie_text = strdup(text), *txtptr; 88 | 89 | switch(type & 0x0f) { 90 | case myMB_OK: 91 | numbut = 1; 92 | button[0] = "[ OK ]"; hotkey[0] = 'O'; ret[0] = myIDOK; 93 | break; 94 | case myMB_OKCANCEL: 95 | numbut = 2; 96 | button[0] = "[ OK ]"; hotkey[0] = 'O'; ret[0] = myIDOK; 97 | button[1] = "[ Cancel ]"; hotkey[1] = 'C'; ret[1] = myIDCANCEL; 98 | break; 99 | case myMB_YESNO: 100 | numbut = 2; 101 | button[0] = "[ Yes ]"; hotkey[0] = 'Y'; ret[0] = myIDYES; 102 | button[1] = "[ No ]"; hotkey[1] = 'N'; ret[1] = myIDNO; 103 | break; 104 | case myMB_YESNOCANCEL: 105 | numbut = 3; 106 | button[0] = "[ Yes ]"; hotkey[0] = 'Y'; ret[0] = myIDYES; 107 | button[1] = "[ No ]"; hotkey[1] = 'N'; ret[1] = myIDNO; 108 | button[2] = "[ Cancel ]"; hotkey[2] = 'C'; ret[2] = myIDCANCEL; 109 | break; 110 | case myMB_RETRYCANCEL: 111 | numbut = 2; 112 | button[0] = "[ Retry ]"; hotkey[0] = 'R'; ret[0] = myIDRETRY; 113 | button[1] = "[ Cancel ]"; hotkey[1] = 'C'; ret[1] = myIDCANCEL; 114 | break; 115 | case myMB_ABORTRETRYIGNORE: 116 | numbut = 3; 117 | button[0] = "[ Abort ]"; hotkey[0] = 'A'; ret[0] = myIDABORT; 118 | button[1] = "[ Retry ]"; hotkey[1]= 'R'; ret[1] = myIDRETRY; 119 | button[2] = "[ Ignore ]"; hotkey[2] = 'I'; ret[2] = myIDIGNORE; 120 | break; 121 | default: 122 | return 0; 123 | } 124 | 125 | sumlen = 0; 126 | for(i=0;i> 4); 157 | if (active < 0 || active >= numbut) 158 | active = 0; 159 | 160 | chosen = -1; 161 | /* interakce */ 162 | while(chosen == -1) { 163 | for(i=0;i (numbut-1) ? 0 : active; 175 | else if (key == KEY_LEFT) 176 | active = --active < 0 ? (numbut-1) : active; 177 | else if (key == 27) /* ESC */ 178 | key = 'C'; /* Cancel */ 179 | else if (key == KEY_MOUSE) { 180 | MEVENT mevent; 181 | if (getmouse(&mevent) == OK && (mevent.bstate & BUTTON1_CLICKED)) { 182 | if (mevent.y == wy + butposy) { 183 | for(i=0;i= butpos[i] && rx <= butpos[i]+strlen(button[i])) { 186 | chosen = i; 187 | break; 188 | } 189 | } 190 | } 191 | else if (mevent.y < wy || mevent.y > wy+wh || mevent.x < wx || mevent.x > wx+ww) 192 | key = 'C'; /* Cancel */ 193 | } 194 | } 195 | for(i=0;i sirka_pole) 343 | pozice_zacatku = kopie_len - sirka_pole + 1; 344 | } 345 | REDRAWROW; 346 | 347 | /* point cursor right after the end of text */ 348 | cursor_pos = strlen(kopie_string); 349 | 350 | update_panels(); 351 | doupdate(); 352 | 353 | curs_set(original_cursor); 354 | while(cursor_pos >= 0 && cursor_pos < maxlen) { 355 | /* scroll with the text in horizontal direction */ 356 | if (RELCURPOS >= sirka_pole) { 357 | pozice_zacatku = cursor_pos - sirka_pole + 1; 358 | REDRAWROW; 359 | } 360 | else if (RELCURPOS <= 0) { 361 | pozice_zacatku = cursor_pos - 1; 362 | if (pozice_zacatku < 0) 363 | pozice_zacatku = 0; 364 | REDRAWROW; 365 | } 366 | 367 | /* show cursor at the right location */ 368 | wmove(w, xrow, xcol + RELCURPOS); 369 | update_panels(); 370 | doupdate(); 371 | switch(key = wgetch(w)) { 372 | case KEY_HELP: 373 | case KEY_F(1): 374 | myMessageBox("Help for ParShell EditBox:\n\nNavigation - arrow keys Right and Left, Home and End\nBackspace and Delete keys erase characters\nCtrl-X or Ctrl-Y keypress erases whole line\nFunction keys F9, F10, Undo or Escape close the EditBox\nReturn or Enter keys end the editting box and send the entered string to ParShell", myMB_OK); 375 | break; 376 | case KEY_F(9): 377 | case KEY_F(10): 378 | case KEY_UNDO: 379 | case 27: /* Escape */ 380 | cursor_pos = -1; /* editing canceled */ 381 | break; 382 | 383 | case '\r': 384 | case '\n': 385 | #ifdef __PDCURSES__ 386 | case PADENTER: 387 | #endif 388 | cursor_pos = maxlen; /* editing confirmed */ 389 | break; 390 | 391 | case KEY_BACKSPACE: 392 | #ifdef __PDCURSES__ 393 | case 8: 394 | #endif 395 | if (cursor_pos == 0) 396 | break; 397 | cursor_pos--; 398 | /* fall through */ 399 | 400 | case KEY_DC: 401 | if (strlen(kopie_string) > cursor_pos) { 402 | memmove(kopie_string+cursor_pos, kopie_string+cursor_pos+1, maxlen-cursor_pos-1); 403 | display_row(RELCURPOS); 404 | } 405 | break; 406 | 407 | case 'X'-64: /* Control-X */ 408 | case 'Y'-64: /* Control-Y */ 409 | memset(kopie_string, 0, maxlen); 410 | cursor_pos = 0; 411 | display_row(RELCURPOS); 412 | break; 413 | 414 | case KEY_LEFT: 415 | if (cursor_pos > 0) 416 | cursor_pos--; 417 | break; 418 | 419 | case KEY_HOME: 420 | cursor_pos = 0; 421 | break; 422 | 423 | case KEY_RIGHT: 424 | if (cursor_pos < strlen(kopie_string)) 425 | cursor_pos++; 426 | break; 427 | 428 | case KEY_END: 429 | cursor_pos = strlen(kopie_string); 430 | break; 431 | 432 | default: 433 | #ifdef __PDCURSES__ 434 | if (key >= KEY_MIN) 435 | #else 436 | if (key & KEY_CODE_YES) 437 | #endif 438 | break; /* it's a special key */ 439 | if (key < ' ') 440 | break; /* Control characters are neither permitted */ 441 | 442 | memmove(kopie_string+cursor_pos+1, kopie_string+cursor_pos, maxlen-cursor_pos-1); 443 | kopie_string[cursor_pos] = key; 444 | display_row(RELCURPOS); 445 | cursor_pos++; 446 | } 447 | } 448 | 449 | curs_set(0); 450 | 451 | del_panel(p); 452 | delwin(w); 453 | update_panels(); 454 | 455 | if (cursor_pos >= 0) 456 | strcpy(return_str, kopie_string); /* copy the resulting string to the 'return_str' */ 457 | free(kopie_string); 458 | return (cursor_pos >= 0); 459 | } 460 | 461 | int EditNumber(const char *title, const char *text, TAG_TYPE tag, void *storage) 462 | { 463 | char number_buf[32]; 464 | 465 | switch(tag) { 466 | case Byte_Tag: 467 | sprintf(number_buf, "%d", *(char *)storage); break; 468 | 469 | case Word_Tag: 470 | sprintf(number_buf, "%d", *(short *)storage); break; 471 | 472 | case Long_Tag: 473 | sprintf(number_buf, "%ld", *(long *)storage); break; 474 | 475 | default: 476 | *number_buf = 0; 477 | } 478 | 479 | if (! EditBox(title, text, number_buf, sizeof(number_buf))) 480 | return FALSE; 481 | 482 | switch(tag) { 483 | case Byte_Tag: 484 | { 485 | int temp; 486 | sscanf(number_buf, "%d", &temp); 487 | *(char *)storage = temp; 488 | } 489 | break; 490 | 491 | case Word_Tag: 492 | sscanf(number_buf, "%hd", (short *)storage); break; 493 | 494 | case Long_Tag: 495 | sscanf(number_buf, "%ld", (long *)storage); break; 496 | 497 | default: 498 | break; 499 | } 500 | return TRUE; 501 | } 502 | -------------------------------------------------------------------------------- /src/partest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PARallel CoPy - written for transferring large files between any two machines 3 | * with parallel ports. 4 | * 5 | * Petr Stehlik (c) 1996-1998 6 | * 7 | */ 8 | 9 | #include "parcp.h" /* konstanty, hlavicky funkci */ 10 | #include "parcplow.h" /* definice ruznych nizkych zalezitosti */ 11 | #include "global.h" /* seznam globalnich promennych */ 12 | #include "parstruc.h" /* konfiguracni struktura */ 13 | #include "match.h" 14 | 15 | #ifdef SHELL 16 | #include 17 | #include 18 | extern MYBOOL curses_initialized; 19 | extern int progress_width; 20 | extern WINDOW *pwincent; 21 | #endif 22 | 23 | MYBOOL client = TRUE; /* PARCP is Client by default */ 24 | 25 | BYTE *block_buffer, *dir_buffer, *file_buffer, string_buffer[MAXSTRING+1]; 26 | long buffer_len = KILO * BUFFER_LENKB; /* velikost prenaseneho bloku */ 27 | #ifdef __MSDOS__ 28 | char original_path[MAXSTRING]; 29 | #endif 30 | 31 | MYBOOL INT_flag = FALSE; /* registruje stisk CTRL-C */ 32 | MYBOOL _quiet_mode = FALSE; /* kdyz je TRUE tak se vubec nic nevypisuje (krome ERRORu) */ 33 | 34 | unsigned long g_files = 0, g_bytes = 0, g_folders = 0; 35 | unsigned long g_files_pos, g_bytes_pos, g_time_pos; 36 | 37 | short page_length = 25; 38 | short page_width = 80; 39 | 40 | int g_last_status = 0; /* CLI will record errors into this var */ 41 | 42 | MYBOOL bInBatchMode = FALSE; 43 | 44 | /******************************************************************************/ 45 | void wait_for_client(void) /* ceka a nezdrzuje zbytek pocitace */ 46 | { 47 | while(IS_READY) { 48 | usleep(WAIT4CLIENT); 49 | if (stop_waiting()) 50 | errexit("Waiting for client interrupted by user.", ERROR_USERSTOP); 51 | } 52 | } 53 | 54 | void wait_before_read(void) /* ceka pred read_neco() aby nevytimeoutoval */ 55 | { 56 | SET_INPUT; 57 | if (client) { 58 | /* musime shodit STROBE aby Server zacal psat */ 59 | STROBE_LOW; 60 | } 61 | while(IS_READY) { 62 | if (stop_waiting()) 63 | errexit("Waiting for other side interrupted by user.", ERROR_USERSTOP); 64 | } 65 | } 66 | 67 | #include "parcplow.c" /* C rutiny, jejichz ekvivalenty mam i v assembleru */ 68 | 69 | void read_block(BYTE *block, long n) 70 | { 71 | long status = 0; 72 | 73 | DPRINT2("l Read_block(%p, %ld)\n", block, n); 74 | 75 | if (client) { 76 | if (_assembler) 77 | status = fast_client_read_block(block, n); 78 | else 79 | status = client_read_block(block, n); 80 | } 81 | else { 82 | if (_assembler) 83 | status = fast_server_read_block(block, n); 84 | else 85 | status = server_read_block(block, n); 86 | } 87 | 88 | if (status < 0) 89 | errexit("Timeout. Please increase Timeout value in PARCP config file.", ERROR_TIMEOUT); 90 | 91 | DPRINT("l Read_block: end\n"); 92 | } 93 | 94 | void write_block(const BYTE *block, long n) 95 | { 96 | long status = 0; 97 | 98 | DPRINT2("l Write_block(%p, %ld)\n", block, n); 99 | 100 | if (client) { 101 | if (_assembler) 102 | status = fast_client_write_block(block, n); 103 | else 104 | status = client_write_block(block, n); 105 | } 106 | else { 107 | if (_assembler) 108 | status = fast_server_write_block(block, n); 109 | else 110 | status = server_write_block(block, n); 111 | } 112 | 113 | if (status < 0) 114 | errexit("Timeout. Please increase Timeout value in PARCP config file.", ERROR_TIMEOUT); 115 | 116 | DPRINT("l Write_block: end\n"); 117 | } 118 | 119 | /******************************************************************************/ 120 | UWORD read_word(void) 121 | { 122 | BYTE a[2+1]; 123 | UWORD x; 124 | 125 | read_block(a,2); 126 | x = (a[0]<<8) | a[1]; 127 | 128 | DPRINT2("l Read_word() -> %u=$%x\n", x, x); 129 | 130 | return x; 131 | } 132 | 133 | long read_long(void) 134 | { 135 | BYTE a[4+1]; 136 | long x; 137 | 138 | read_block(a,4); 139 | x = a[0]; 140 | x = (x<<8) | a[1]; 141 | x = (x<<8) | a[2]; 142 | x = (x<<8) | a[3]; 143 | 144 | DPRINT2("l Read_long() -> %ld=$%lx\n", x, x); 145 | 146 | return x; 147 | } 148 | 149 | void write_word(UWORD x) 150 | { 151 | BYTE a[2+1]; 152 | a[0] = x>>8; 153 | a[1] = x; 154 | 155 | DPRINT2("l Write_word(%u=$%x)\n", x, x); 156 | 157 | write_block(a,2); 158 | } 159 | 160 | void write_long(long x) 161 | { 162 | BYTE a[4+1]; 163 | 164 | a[3] = x; 165 | a[2] = (x = x>>8); 166 | a[1] = (x = x>>8); 167 | a[0] = x>>8; 168 | 169 | DPRINT2("l Write_long(%ld=$%lx)\n", x, x); 170 | 171 | write_block(a,4); 172 | } 173 | 174 | /*******************************************************************************/ 175 | 176 | void catch_ctrl_c(int x) 177 | { 178 | if (! INT_flag) 179 | INT_flag = TRUE; /* zaznamenat stisknuti klavesy */ 180 | signal(SIGINT, catch_ctrl_c); 181 | } 182 | 183 | /* return TRUE if user holds EmergencyQuit keys */ 184 | /* EmergencyQuit keys are either Alt+Shift+Control or Control-C */ 185 | MYBOOL stop_waiting(void) 186 | { 187 | MYBOOL was_break = INT_flag; 188 | 189 | #ifdef KEYPRESSED 190 | if (KEYPRESSED >= 13) /* Alt+Shift+Control */ 191 | was_break = TRUE; 192 | #endif 193 | 194 | INT_flag = FALSE; /* v kazdem pripade vymazat flag CTRL-C */ 195 | 196 | return was_break; 197 | } 198 | 199 | /* return TRUE if user holds Stop-File-Transfer keys on Client */ 200 | /* Stop-File-Transfer keys are either Shif+Control or Control-C */ 201 | MYBOOL break_file_transfer(void) 202 | { 203 | MYBOOL was_break = INT_flag; 204 | 205 | #ifdef KEYPRESSED 206 | if (KEYPRESSED == 6 || KEYPRESSED == 7) /* Shift+Control */ 207 | was_break = TRUE; 208 | #endif 209 | 210 | INT_flag = FALSE; /* clear flag CTRL-C */ 211 | 212 | return was_break; 213 | } 214 | 215 | /* return TRUE if user pressed Esc key on Client */ 216 | MYBOOL zastavit_prenos_souboru(void) 217 | { 218 | if (client) { 219 | int keys = 0; 220 | 221 | /* 222 | else 223 | keys = fetch_key(); 224 | */ 225 | 226 | if (keys == 27) /* ESC key */ 227 | return TRUE; 228 | 229 | #ifdef ATARI 230 | #ifdef KEYPRESSED 231 | if (KEYPRESSED == 3) /* both shifts */ 232 | return TRUE; 233 | #endif 234 | #endif 235 | } 236 | return FALSE; 237 | } 238 | 239 | /*******************************************************************************/ 240 | void port_reset(void) 241 | { 242 | SET_INPUT; 243 | STROBE_HIGH; 244 | #ifdef IBM 245 | if (port_type == 2 && !PCunidirect) 246 | EPP2ECP; 247 | #endif 248 | } 249 | /*******************************************************************************/ 250 | 251 | void errexit(const char *a, int error_code) 252 | { 253 | DPRINT1("! Errexit: %s\n", a); 254 | port_reset(); 255 | puts(""); 256 | if (a != NULL) 257 | puts(a); 258 | else 259 | puts("An unknown error occured."); 260 | 261 | 262 | /* 263 | puts("Press Return to exit."); 264 | getchar(); 265 | */ 266 | exit(error_code); 267 | } 268 | /*******************************************************************************/ 269 | 270 | char *get_cwd(char *path, int maxlen) 271 | { 272 | getcwd(path, maxlen); 273 | #ifdef ATARI 274 | if (! strncmp(path,TOS_DEV,Ltos_dev)) { 275 | DPRINT1("> Get_cwd() = '%s' but will be converted\n", path); 276 | memmove(path, path+Ltos_dev-1, strlen(path)-Ltos_dev+2); /* odstranit /dev/ */ 277 | if (path[2] == SLASH) { /* je to /x/ */ 278 | path[0] = path[1]; 279 | path[1] = DVOJTEKA; /* prevedu na x:/ */ 280 | } 281 | } 282 | #endif 283 | DPRINT1("> Get_cwd() = '%s'\n", path); 284 | return path; 285 | } 286 | /*******************************************************************************/ 287 | 288 | int config_file(const char *soubor, MYBOOL vytvorit) 289 | { 290 | int vysledek; 291 | 292 | if (vytvorit) { 293 | buffer_lenkb = buffer_len / KILO; 294 | vysledek = update_config(soubor,configs,CFGHEAD); 295 | } 296 | else { 297 | vysledek = input_config(soubor,configs,CFGHEAD); 298 | 299 | if (dirbuf_lines < 1) 300 | dirbuf_lines = 1; 301 | 302 | if (time_out < 1) 303 | time_out = 1; 304 | 305 | buffer_len = buffer_lenkb * KILO; 306 | 307 | #ifdef DEBUG 308 | /* pokud neni logfile s cestou, musim doplnit aktualni */ 309 | if (!strchr(logfile, SLASH) && !strchr(logfile, BACKSLASH)) { 310 | char cesta[MAXPATH], *p; 311 | 312 | getcwd(cesta, sizeof(cesta)); 313 | p = cesta + strlen(cesta)-1; 314 | if (*p != SLASH && *p != BACKSLASH) 315 | strcat(cesta, SLASH_STR); 316 | strcat(cesta, logfile); 317 | strcpy(logfile, cesta); 318 | } 319 | #endif 320 | } 321 | 322 | return vysledek; 323 | } 324 | /*******************************************************************************/ 325 | void inicializace(void) 326 | { 327 | #ifdef __MSDOS__ 328 | getcwd(original_path, sizeof(original_path)); /* pamatuj puvodni cestu */ 329 | #endif 330 | 331 | #ifndef STANDALONE 332 | 333 | #ifdef IBM 334 | if (! _quiet_mode) { 335 | printf("Parallel port base address: %x\n", print_port); 336 | printf("Parallel port type: "); 337 | switch(port_type) { 338 | case 0: printf("unidirectional/ECP unable to switch to EPP\n"); break; 339 | case 1: printf("bidirectional/EPP\n"); break; 340 | case 2: printf("ECP switched to EPP\n"); break; 341 | } 342 | printf("Cable type: %s\n", cable_type ? "PARCP bidirectional" : "LapLink"); 343 | if (cable_type) { 344 | if (PCunidirect) 345 | puts("UNI-BI HW parallel adapter has to be plugged-in."); 346 | else { 347 | if (port_type) 348 | puts("No HW adapter - PARCP cable is enough."); 349 | else 350 | errexit("Bidirectional routines on unidirectional port? Never!\n"\ 351 | "Run PARCPCFG.EXE in order to correct your PARCP setup.", ERROR_BADCFG); 352 | } 353 | } 354 | else 355 | if (PCunidirect) 356 | errexit("UNI-BI HW parallel adapter and LapLink parallel cable? Bad idea!\n"\ 357 | "Choose either UNI-BI adapter or LapLink cable - run PARCPCFG.EXE.", ERROR_BADCFG); 358 | } 359 | 360 | #ifdef __LINUX__ 361 | /* v Linuxu si vyhradim pravo pristupu na hardware paralelniho portu */ 362 | 363 | /* zkusme zkontrolovat, ma-li uzivatel prava ROOTa */ 364 | 365 | DPRINT("> Trying to get permisions to in/out the port directly\n"); 366 | if (iopl(0)) { 367 | errexit("Need root privileges to drive parallel port\n", ERROR_NOTROOT); 368 | } 369 | ioperm(print_port,4,1); 370 | #endif /* __LINUX__ */ 371 | 372 | if (port_type == 2 && !PCunidirect) 373 | ECP2EPP; 374 | 375 | #endif /* IBM */ 376 | 377 | #endif /* STANDALONE */ 378 | } 379 | 380 | /*******************************************************************************/ 381 | 382 | void client_server_handshaking(MYBOOL client) 383 | { 384 | SET_INPUT; 385 | STROBE_HIGH; 386 | 387 | if (client) { 388 | printf("\n[Test Client] (will timeout in %d seconds)\n", time_out); 389 | 390 | /* protokol neni dost robustni: budu vyzadovat start Serveru pred spustenim Clienta */ 391 | if (! IS_READY) 392 | errexit("Server has NOT been started yet - or a problem occured with parallel cable.\n"\ 393 | "Check your HW and PARCP configuration, then start Server *BEFORE* Client.", ERROR_HANDSHAKE); 394 | 395 | usleep(2*WAIT4CLIENT); /* podrzet STROBE HIGH na chvilku, aby nas Server odlisil od nestavu */ 396 | 397 | } 398 | else { 399 | printf("\n[Test Server] Awaiting data patterns from Test Client (press %s to quit)\n", STOP_KEYSTROKE); 400 | 401 | /* pokud je BUSY LOW, druha strana je v nestavu */ 402 | /* NESMIM zamenit s predcasne spustenym klientem! */ 403 | while(! IS_READY) { 404 | usleep(WAIT4CLIENT); 405 | if (stop_waiting()) 406 | errexit("Waiting for client startup interrupted by user.", ERROR_HANDSHAKE); 407 | } 408 | } 409 | } 410 | 411 | /*******************************************************************************/ 412 | 413 | #include "parcommo.c" 414 | 415 | int zpracovani_parametru(int argc, char *argv[]) 416 | { 417 | char cesta[MAXPATH], batch_file[MAXPATH]; 418 | int i; 419 | extern int optind; 420 | extern char *optarg; 421 | MYBOOL konfigOK = FALSE; 422 | 423 | batch_file[0] = 0; 424 | 425 | /* nejdrive podle priorit najdu konfiguracni soubor */ 426 | konfigOK = hledej_config(argv, cesta); 427 | 428 | /* nyni projdu parametry prikazoveho radku, ktere tak maji vyssi prioritu */ 429 | 430 | #define ARG_OPTIONS "sf:b:q" 431 | 432 | while((i=getopt(argc, argv, ARG_OPTIONS)) != EOF) { 433 | switch(tolower(i)) { 434 | case 's': 435 | client = FALSE; 436 | break; 437 | 438 | case 'f': 439 | strcpy(cesta, optarg); 440 | konfigOK = file_existuje(cesta); 441 | break; 442 | 443 | case 'b': 444 | strcpy(batch_file, optarg); 445 | break; 446 | 447 | case 'q': 448 | _quiet_mode = TRUE; 449 | break; 450 | 451 | case '?': 452 | puts(USAGE); exit(1); 453 | } 454 | } 455 | 456 | if (konfigOK) { 457 | int valid_num = 0; 458 | if (! _quiet_mode) 459 | printf("Configuration file used: %s\n", cesta); 460 | 461 | valid_num = config_file(cesta, FALSE); 462 | 463 | if (! _quiet_mode) { 464 | if (valid_num >= 0) 465 | printf("(valid directives found: %d)\n\n", valid_num); 466 | else 467 | printf("Error while reading/processing the config file.\n\n"); 468 | } 469 | } 470 | else { 471 | /* konfiguracni soubor nenalezen! */ 472 | #ifdef ATARI 473 | /* na Atari ho proste vytvorim s defaultnimi hodnotami */ 474 | if (! _quiet_mode) 475 | printf("Configuration file not found.\nIt's being created: %s\n\n", cesta); 476 | DPRINT1("! Creating configuration file: %s\n", cesta); 477 | config_file(cesta, TRUE); 478 | #else 479 | /* na strojich, kde zalezi na adrese a typu portu, vsak musim koncit */ 480 | #ifndef STANDALONE 481 | printf("PARCP configuration file (%s) not found.\nPlease start PARCPCFG in order to create it\n", cesta); 482 | exit(ERROR_BADCFG); 483 | #endif /* STANDALONE */ 484 | #endif /* ATARI */ 485 | } 486 | 487 | if (*batch_file) 488 | strcpy(autoexec, batch_file); /* presun parametr do struktury */ 489 | 490 | strcpy(cfg_fname, cesta); /* dobre si zapamatovat, ktery konfiguracni soubor pouzivame */ 491 | 492 | return optind; /* vracim cislo prvniho NEparametru (tj. jmena souboru) */ 493 | } 494 | 495 | MYBOOL test(UWORD x) 496 | { 497 | UWORD y; 498 | MYBOOL result; 499 | 500 | printf("Sending %04x\t", x); 501 | write_word(x); 502 | printf("Receiving "); 503 | y = read_word(); 504 | printf("%04x\t", y); 505 | result = (x == y); 506 | if (result) 507 | printf("OK\n"); 508 | else 509 | printf("ERROR!\n"); 510 | 511 | return result; 512 | } 513 | 514 | int main(int argc, char *argv[]) 515 | { 516 | #if defined(DEBUG) 517 | time_t start_time = time(NULL); 518 | #endif 519 | int i; 520 | 521 | setvbuf(stdout,NULL,_IONBF,0); /* vypnu bufrovani vystupu na obrazovku */ 522 | signal(SIGINT, catch_ctrl_c); /* nastavim ovladac CTRL-C */ 523 | INT_flag = FALSE; /* vynuluju priznak stisku CTRL-C */ 524 | 525 | clrscr(); /* smazu obrazovku */ 526 | 527 | /* 528 | { 529 | int i; 530 | for(i=1; i>*/ 37 | 38 | #ifndef Boolean_T_defined 39 | #define Boolean_T_defined 40 | 41 | typedef enum { 42 | FALSE, TRUE 43 | } Boolean_T; 44 | #define ERROR -1 45 | #endif 46 | 47 | /*---------------------------------------------------------------------/ 48 | / 49 | / Description: CfgOpts is based on GETOPTS by Bob Stout. It will 50 | / process a configuration file based one words and 51 | / store it in a structure pointing to physical data 52 | / area for each storage item. 53 | / i.e. ???.CFG: 54 | / Port=1 55 | / work_space=C:\temp 56 | / menus=TRUE 57 | / user=Jeffry Brickley 58 | / will write to the following structure: 59 | / struct Config_Tag configs[] = { 60 | / {"port", Word_Tag, &port_number}, 61 | / {"work_space", String_Tag, work_space, sizeof(work_space)}, 62 | / {"menus", Boolean_Tag, &menu_flag}, 63 | / {"user", String_Tag, User_name, sizeof(User_name)}, 64 | / {NULL, Error_Tag, NULL} 65 | / }; 66 | / Note that the structure must always be terminated by a NULL row as 67 | / was the same with GETOPTS. This however is slightly more 68 | / complicated than scaning the command line (but not by much) for 69 | / data as there can be more variety in words than letters and an 70 | / number of data items limited only by memory. Currently CfgOpts 71 | / is not case sensitive, but this can be changed by replacing all 72 | / "strcasecmp" functions with "strcmp" functions. 73 | / 74 | / Like the original code from which this was taken, this is released 75 | / to the Public Domain. I cannot make any guarentees other than these 76 | / work for me and I find them usefull. Feel free to pass these on to 77 | / a friend, but please do not charge him.... 78 | / 79 | /---------------------------------------------------------------------*/ 80 | 81 | #include 82 | #include 83 | #include 84 | #include "cfgopts.h" 85 | 86 | char *trim(char *buffer) 87 | { 88 | #define SPACE ' ' 89 | #define TABULA '\t' 90 | 91 | if (buffer != NULL) { 92 | int i, linelen = strlen(buffer); 93 | 94 | for (i = 0; i < linelen; i++) 95 | if (buffer[i] != SPACE && buffer[i] != TABULA) 96 | break; 97 | 98 | if (i > 0 && i < linelen) { 99 | linelen -= i; 100 | memmove(buffer, buffer + i, linelen); /* mezery zleva pryc */ 101 | } 102 | 103 | for (i = linelen; i > 0; i--) { 104 | int j = i-1; 105 | if (buffer[j] != SPACE && buffer[j] != TABULA) 106 | break; 107 | } 108 | 109 | buffer[i] = '\0'; /* mezery zprava pryc */ 110 | } 111 | 112 | return buffer; 113 | } 114 | 115 | 116 | char *strip_comment(char *line) 117 | { 118 | #define REM1 '#' 119 | #define REM2 ';' 120 | int i, j; 121 | 122 | if (line == NULL) 123 | return NULL; 124 | 125 | j = strlen(line); 126 | for (i = 0; i < j; i++) 127 | if (line[i] == REM1 || line[i] == REM2) { 128 | line[i] = '\0'; 129 | break; 130 | } 131 | 132 | return line; 133 | } 134 | 135 | 136 | static char line[1024]; 137 | 138 | /* 139 | * FCOPY.C - copy one file to another. Returns the (positive) 140 | * number of bytes copied, or -1 if an error occurred. 141 | * by: Bob Jarvis 142 | */ 143 | 144 | /*---------------------------------------------------------------------/ 145 | / copy one file to another. 146 | /---------------------------------------------------------------------*/ 147 | /*>>------[ fcopy() ]-------------[ 08-02-95 14:02PM ]------/ 148 | / return value: 149 | / long ; Number of bytes copied or -1 on error 150 | / parameters: 151 | / char *dest ; Destination file name 152 | / char *source ; Source file name 153 | /-------------------------------------------------------------------<<*/ 154 | long fcopy(const char *dest, const char *source) 155 | { 156 | FILE * d, *s; 157 | size_t incount, outcount; 158 | long totcount = 0L; 159 | 160 | s = fopen(source, "rb"); 161 | if (s == NULL) 162 | return - 1L; 163 | 164 | d = fopen(dest, "wb"); 165 | if (d == NULL) { 166 | fclose(s); 167 | return - 1L; 168 | } 169 | 170 | incount = fread(line, sizeof(char), sizeof(line), s); 171 | outcount = 0; 172 | 173 | while (!feof(s)) { 174 | totcount += (long)incount; 175 | outcount += fwrite(line, sizeof(char), incount, d); 176 | incount = fread(line, sizeof(char), sizeof(line), s); 177 | } 178 | 179 | totcount += (long)incount; 180 | outcount += fwrite(line, sizeof(char), incount, d); 181 | 182 | fclose(s); 183 | fclose(d); 184 | 185 | if (outcount < incount) 186 | return -1L; /* disk full? */ 187 | 188 | return totcount; 189 | } 190 | 191 | 192 | /*---------------------------------------------------------------------/ 193 | / reads from an input configuration (INI) file. 194 | /---------------------------------------------------------------------*/ 195 | /*>>------[ input_config() ]-------------[ 08-02-95 14:02PM ]------/ 196 | / return value: 197 | / int ; number of records read or -1 on error 198 | / parameters: 199 | / char *filename ; filename of INI style file 200 | / struct Config_Tag configs[]; Configuration structure 201 | / char *header ; INI header name (i.e. "[TEST]") 202 | /-------------------------------------------------------------------<<*/ 203 | int input_config(const char *filename, struct Config_Tag configs[], char *header) 204 | { 205 | int count = 0, lineno = 0; 206 | 207 | FILE *file = fopen(filename, "rt"); 208 | if ( file == NULL ) 209 | return ERROR; /* return error designation. */ 210 | if ( header != NULL ) 211 | do { 212 | trim(fgets(line, sizeof(line), file)); /* get input line */ 213 | } while ( memcmp(line, header, strlen(header)) && !feof(file)); 214 | 215 | if ( !feof(file) ) { 216 | char *fptr, *tok; 217 | do { 218 | fptr = trim(fgets(line, sizeof(line), file)); /* get input line */ 219 | if ( fptr == NULL ) 220 | continue; 221 | lineno++; 222 | strip_comment(line); 223 | 224 | if ( line[0] == '[' ) 225 | continue; /* next header is the end of our section */ 226 | 227 | tok = trim(strtok(line, "=\n\r")); /* get first token */ 228 | if ( tok != NULL ) { 229 | struct Config_Tag *ptr; 230 | char *next = trim(strtok(NULL, "=\n\r")); /* get actual config information */ 231 | for ( ptr = configs; ptr->buf; ++ptr ) /* scan for token */ { 232 | if ( !strcasecmp( tok , ptr->code ) ) /* got a match? */ { 233 | int temp; 234 | if (next == NULL) { 235 | if ( ptr->type == String_Tag ) {/* string may be empty */ 236 | *(char *)ptr->buf = 0; 237 | ++count; 238 | } 239 | else { 240 | fprintf(stderr, ">>> Missing value in Config file %s on line %d !!!\n", filename, lineno); 241 | } 242 | continue; 243 | } 244 | switch ( ptr->type ) /* check type */ { 245 | case Boolean_Tag: 246 | *((Boolean_T * )(ptr->buf)) = (!strcasecmp(next, "FALSE") || !strcasecmp(next, "No")) ? FALSE : TRUE; 247 | ++count; 248 | break; 249 | 250 | case Byte_Tag: 251 | sscanf(next, "%d", &temp); 252 | *((char *)(ptr->buf)) = (char)temp; 253 | ++count; 254 | break; 255 | 256 | case Word_Tag: 257 | sscanf(next, "%hd", (short *)(ptr->buf)); 258 | ++count; 259 | break; 260 | 261 | case Int_Tag: 262 | sscanf(next, "%d", (int *)(ptr->buf)); 263 | ++count; 264 | break; 265 | 266 | case Long_Tag: 267 | sscanf(next, "%ld", (long *)(ptr->buf)); 268 | ++count; 269 | break; 270 | 271 | case HexWord_Tag: 272 | sscanf(next, "%hx", (short *)(ptr->buf)); 273 | ++count; 274 | break; 275 | 276 | case HexInt_Tag: 277 | sscanf(next, "%x", (int *)(ptr->buf)); 278 | ++count; 279 | break; 280 | 281 | case HexLong_Tag: 282 | sscanf(next, "%lx", (long *)(ptr->buf)); 283 | ++count; 284 | break; 285 | 286 | case Float_Tag: 287 | sscanf(next, "%g", (float *)ptr->buf); 288 | ++count; 289 | break; 290 | 291 | case Double_Tag: 292 | sscanf(next, "%lg", (double *)ptr->buf); 293 | ++count; 294 | break; 295 | 296 | case Char_Tag: 297 | *(char *)ptr->buf = *next; 298 | ++count; 299 | break; 300 | 301 | case String_Tag: 302 | if (ptr->buf_size > 0) { 303 | strncpy((char *)ptr->buf, next, ptr->buf_size); 304 | *(char *)(ptr->buf + ptr->buf_size - 1) = 0; /* EOS */ 305 | ++count; 306 | } 307 | else { 308 | fprintf(stderr, ">>> Wrong buf_size in Config_Tag struct: directive %s, buf_size %d !!!\n", ptr->code, ptr->buf_size); 309 | } 310 | break; 311 | 312 | case Function_Tag: 313 | case Error_Tag: 314 | default: 315 | printf("Error in Config file %s on line %d\n", 316 | filename, lineno); 317 | break; 318 | } 319 | } 320 | } 321 | } 322 | } while ( fptr != NULL && line[0] != '['); 323 | } 324 | fclose(file); 325 | return count; 326 | } 327 | 328 | Boolean_T write_token(FILE *outfile, struct Config_Tag *ptr) 329 | { 330 | int temp; 331 | Boolean_T ret_flag = TRUE; 332 | 333 | ptr->stat = 1; /* jiz ulozeno do souboru */ 334 | 335 | fprintf(outfile, "%s = ", ptr->code); 336 | switch ( ptr->type ) /* check type */ { 337 | case Boolean_Tag: 338 | fprintf(outfile, "%s\n", *((Boolean_T *)(ptr->buf)) ? "Yes" : "No"); 339 | break; 340 | 341 | case Byte_Tag: 342 | temp = (int)*((char *)(ptr->buf)); 343 | fprintf(outfile, "%hd\n", temp); 344 | break; 345 | 346 | case Word_Tag: 347 | fprintf(outfile, "%hd\n", *((short *)(ptr->buf))); 348 | break; 349 | 350 | case Int_Tag: 351 | fprintf(outfile, "%d\n", *((int *)(ptr->buf))); 352 | break; 353 | 354 | case Long_Tag: 355 | fprintf(outfile, "%ld\n", *((long *)(ptr->buf))); 356 | break; 357 | 358 | case HexWord_Tag: 359 | fprintf(outfile, "%hx\n", *((short *)(ptr->buf))); 360 | break; 361 | 362 | case HexInt_Tag: 363 | fprintf(outfile, "%x\n", *((int *)(ptr->buf))); 364 | break; 365 | 366 | case HexLong_Tag: 367 | fprintf(outfile, "%lx\n", *((long *)(ptr->buf))); 368 | break; 369 | 370 | case Float_Tag: 371 | fprintf(outfile, "%g\n", *((float *)ptr->buf)); 372 | break; 373 | 374 | case Double_Tag: 375 | fprintf(outfile, "%g\n", *((double *)ptr->buf)); 376 | break; 377 | 378 | case Char_Tag: 379 | fprintf(outfile, "%c\n", *(char *)ptr->buf); 380 | break; 381 | 382 | case String_Tag: 383 | fprintf(outfile, "%s\n", (char *)ptr->buf); 384 | break; 385 | 386 | case Error_Tag: 387 | case Function_Tag: 388 | default: 389 | printf("Error in Config structure (Contact author).\n"); 390 | ret_flag = FALSE; 391 | } 392 | return ret_flag; 393 | } 394 | 395 | /*---------------------------------------------------------------------/ 396 | / updates an input configuration (INI) file from a structure. 397 | /---------------------------------------------------------------------*/ 398 | /*>>------[ update_config() ]-------------[ 08-02-95 14:02PM ]------/ 399 | / return value: 400 | / int ; Number of records read & updated 401 | / parameters: 402 | / char *filename ; filename of INI file 403 | / struct Config_Tag configs[]; Configuration structure 404 | / char *header ; INI header name (i.e. "[TEST]") 405 | /-------------------------------------------------------------------<<*/ 406 | int update_config(const char *filename, struct Config_Tag configs[], char *header) 407 | { 408 | struct Config_Tag *ptr; 409 | int count = 0, lineno = 0; 410 | FILE * infile, *outfile; 411 | char *fptr, *tok; 412 | int result = 0; 413 | 414 | for ( ptr = configs; ptr->buf; ++ptr ) 415 | ptr->stat = 0; /* jeste neulozeno do souboru */ 416 | 417 | infile = fopen(filename, "rt"); 418 | if ( infile == NULL ) { 419 | /* konfiguracni soubor jeste vubec neexistuje */ 420 | outfile = fopen("temp.$$$", "wt"); 421 | if ( outfile == NULL ) 422 | return ERROR; /* return error designation. */ 423 | if ( header != NULL ) { 424 | fprintf(outfile, "%s\n", header); 425 | } 426 | for ( ptr = configs; ptr->buf; ++ptr ) /* scan for token */ { 427 | if ( write_token(outfile, ptr) ) 428 | ++count; 429 | } 430 | 431 | fclose(outfile); 432 | result = fcopy(filename, "temp.$$$"); 433 | remove("temp.$$$"); 434 | 435 | if (result < 0) 436 | return result; 437 | return count; 438 | } 439 | outfile = fopen("temp.$$$", "wt"); 440 | if ( outfile == NULL ) { 441 | fclose(infile); 442 | return ERROR; /* return error designation. */ 443 | } 444 | if ( header != NULL ) { 445 | /* konfiguracni soubor existuje a je otevren - hledame nasi sekci */ 446 | do { 447 | fptr = trim(fgets(line, sizeof(line), infile)); /* get input line */ 448 | if (feof(infile)) 449 | break; 450 | 451 | fprintf(outfile, "%s", line); 452 | } while ( memcmp(line, header, strlen(header))); 453 | } 454 | if ( feof(infile) ) { 455 | /* v jiz existujicim konfiguracnim souboru neni sekce, kterou zapisujeme */ 456 | 457 | if ( header != NULL ) { 458 | fprintf(outfile, "\n%s\n", header); 459 | } 460 | for ( ptr = configs; ptr->buf; ++ptr ) /* scan for token */ { 461 | if ( write_token(outfile, ptr) ) 462 | ++count; 463 | } 464 | } else { 465 | /* v jiz existujicim souboru byla nalezena sekce, kterou mame updatovat */ 466 | for (;;) { 467 | fptr = trim(fgets(line, sizeof(line), infile)); /* get input line */ 468 | if ( fptr == NULL ) 469 | break; 470 | lineno++; 471 | if ( line[0] == REM1 || line[0] == REM2 ) { 472 | fprintf(outfile, "%s", line); 473 | continue; /* skip comments */ 474 | } 475 | if ( line[0] == '[' || feof(infile) ) { /* konec nasi sekce */ 476 | break; /* zbytek konfig. souboru jen opis z puvodniho */ 477 | } 478 | 479 | tok = trim(strtok(line, "=\n\r")); /* get first token */ 480 | if ( tok != NULL ) { 481 | for ( ptr = configs; ptr->buf; ++ptr ) /* scan for token */ { 482 | if ( !strcasecmp( tok , ptr->code ) ) /* got a match? */ { 483 | if ( write_token(outfile, ptr) ) { 484 | ++count; 485 | } 486 | } 487 | } 488 | } 489 | } 490 | /* nasli jsme zacatek dalsi sekce - tedy zkoncila nase sekce. Nyni je nutne 491 | zjistit, ktere radky struktury jsme jeste neupdatovali a ty tam v podstate 492 | zapsat jako by konfiguracni soubor ani neexistoval */ 493 | 494 | for ( ptr = configs; ptr->buf; ++ptr ) { 495 | if (ptr->stat == 0) 496 | if ( write_token(outfile, ptr) ) 497 | ++count; 498 | } 499 | 500 | if ( !feof(infile) && fptr != NULL) 501 | fprintf(outfile, "\n%s", line);/* doplnit prvni radku dalsi sekce */ 502 | 503 | /* zkopirovat zbytek konfiguracniho souboru (cizi sekce) */ 504 | for(;;) { 505 | fptr = trim(fgets(line, sizeof(line), infile)); /* get input line */ 506 | if (feof(infile)) 507 | break; 508 | 509 | fprintf(outfile, "%s", line); 510 | } 511 | } 512 | fclose(infile); 513 | fclose(outfile); 514 | result = fcopy(filename, "temp.$$$"); 515 | remove("temp.$$$"); 516 | 517 | if (result < 0) 518 | return result; 519 | return count; 520 | } 521 | 522 | 523 | #ifdef TEST 524 | 525 | #include 526 | 527 | Boolean_T test1 = TRUE, test2 = FALSE; 528 | short test3 = -37; 529 | long test4 = 100000L; 530 | char test5[80] = "Default string"; 531 | 532 | struct Config_Tag configs[] = { 533 | { "test1", Boolean_Tag, &test1 }, /* Valid options */ 534 | { "test2", Boolean_Tag, &test2 }, 535 | { "test3", Word_Tag, &test3 }, 536 | { "test4", Long_Tag, &test4 }, 537 | { "test5", String_Tag, test5, sizeof(test5) }, 538 | { NULL , Error_Tag, NULL }/* Terminating record */ 539 | 540 | }; 541 | 542 | 543 | #define TFprint(v) ((v) ? "TRUE" : "FALSE") 544 | 545 | /*---------------------------------------------------------------------/ 546 | / test main routine, read/write to a sample INI file. 547 | /---------------------------------------------------------------------*/ 548 | /*>>------[ main() ]-------------[ 08-02-95 14:02PM ]------/ 549 | / return value: 550 | / int ; 0 551 | / parameters: 552 | / int argc ; number of arguments 553 | / char *argv[] ; command line arguments 554 | /-------------------------------------------------------------------<<*/ 555 | int main(int argc, char *argv[]) 556 | { 557 | int i; 558 | printf("Defaults:\ntest1 = %s\ntest2 = %s\ntest3 = %d\ntest4 = %ld\n" 559 | "test5 = \"%s\"\n\n", TFprint(test1), TFprint(test2), test3, 560 | test4, test5); 561 | 562 | printf("input_config() returned %d\n", 563 | input_config("test.cfg", configs, "[TEST1]")); 564 | 565 | printf("Options are now:\ntest1 = %s\ntest2 = %s\ntest3 = %d\n" 566 | "test4 = %ld\ntest5 = \"%s\"\n\n", TFprint(test1), 567 | TFprint(test2), test3, test4, test5); 568 | 569 | #ifdef TEST_UPDATE 570 | test1 = TRUE; 571 | test2 = FALSE; 572 | test3 = -37; 573 | test4 = 100000L; 574 | strcpy(test5, "Default value"); 575 | 576 | printf("update_config() returned %d\n", 577 | update_config("test.cfg", configs, "[TEST2]")); 578 | 579 | printf("Options are now:\ntest1 = %s\ntest2 = %s\ntest3 = %d\n" 580 | "test4 = %ld\ntest5 = \"%s\"\n\n", TFprint(test1), 581 | TFprint(test2), test3, test4, test5); 582 | #endif 583 | 584 | return 0; 585 | } 586 | 587 | 588 | #endif 589 | 590 | -------------------------------------------------------------------------------- /src/match.c: -------------------------------------------------------------------------------- 1 | /* 2 | EPSHeader 3 | 4 | File: match.c 5 | Author: J. Kercheval 6 | Created: Sat, 01/05/1991 22:21:49 7 | */ 8 | /* 9 | EPSRevision History 10 | 11 | J. Kercheval Wed, 02/20/1991 22:29:01 Released to Public Domain 12 | J. Kercheval Fri, 02/22/1991 15:29:01 fix '\' bugs (two :( of them) 13 | J. Kercheval Sun, 03/10/1991 19:31:29 add error return to matche() 14 | J. Kercheval Sun, 03/10/1991 20:11:11 add is_valid_pattern code 15 | J. Kercheval Sun, 03/10/1991 20:37:11 beef up main() 16 | J. Kercheval Tue, 03/12/1991 22:25:10 Released as V1.1 to Public Domain 17 | */ 18 | 19 | /* 20 | Wildcard Pattern Matching 21 | */ 22 | 23 | 24 | #include "match.h" 25 | 26 | int matche_after_star (register char *pattern, register char *text, MYBOOL case_sensitive); 27 | 28 | /*---------------------------------------------------------------------------- 29 | * 30 | * Return TRUE if PATTERN has any special wildcard characters 31 | * 32 | ----------------------------------------------------------------------------*/ 33 | 34 | MYBOOL is_pattern (char *p) 35 | { 36 | while (*p) 37 | { 38 | switch (*p++) 39 | { 40 | case '?': 41 | case '*': 42 | case '[': 43 | case '\\': 44 | return TRUE; 45 | } 46 | } 47 | return FALSE; 48 | } 49 | 50 | 51 | /*---------------------------------------------------------------------------- 52 | * 53 | * Return TRUE if PATTERN has is a well formed regular expression according 54 | * to the above syntax 55 | * 56 | * error_type is a return code based on the type of pattern error. Zero is 57 | * returned in error_type if the pattern is a valid one. error_type return 58 | * values are as follows: 59 | * 60 | * PATTERN_VALID - pattern is well formed 61 | * PATTERN_ESC - pattern has invalid escape ('\' at end of pattern) 62 | * PATTERN_RANGE - [..] construct has a no end range in a '-' pair (ie [a-]) 63 | * PATTERN_CLOSE - [..] construct has no end bracket (ie [abc-g ) 64 | * PATTERN_EMPTY - [..] construct is empty (ie []) 65 | * 66 | ----------------------------------------------------------------------------*/ 67 | 68 | MYBOOL is_valid_pattern (char *p, int *error_type) 69 | { 70 | /* init error_type */ 71 | *error_type = PATTERN_VALID; 72 | 73 | /* loop through pattern to EOS */ 74 | while (*p) 75 | { 76 | /* determine pattern type */ 77 | switch (*p) 78 | { 79 | /* check literal escape, it cannot be at end of pattern */ 80 | case '\\': 81 | if (!*++p) 82 | { 83 | *error_type = PATTERN_ESC; 84 | return FALSE; 85 | } 86 | p++; 87 | break; 88 | 89 | /* the [..] construct must be well formed */ 90 | case '[': 91 | p++; 92 | 93 | /* if the next character is ']' then bad pattern */ 94 | if (*p == ']') 95 | { 96 | *error_type = PATTERN_EMPTY; 97 | return FALSE; 98 | } 99 | 100 | /* if end of pattern here then bad pattern */ 101 | if (!*p) 102 | { 103 | *error_type = PATTERN_CLOSE; 104 | return FALSE; 105 | } 106 | 107 | /* loop to end of [..] construct */ 108 | while (*p != ']') 109 | { 110 | /* check for literal escape */ 111 | if (*p == '\\') 112 | { 113 | p++; 114 | 115 | /* if end of pattern here then bad pattern */ 116 | if (!*p++) 117 | { 118 | *error_type = PATTERN_ESC; 119 | return FALSE; 120 | } 121 | } 122 | else p++; 123 | 124 | /* if end of pattern here then bad pattern */ 125 | if (!*p) 126 | { 127 | *error_type = PATTERN_CLOSE; 128 | return FALSE; 129 | } 130 | 131 | /* if this a range */ 132 | if (*p == '-') 133 | { 134 | /* we must have an end of range */ 135 | if (!*++p || *p == ']') 136 | { 137 | *error_type = PATTERN_RANGE; 138 | return FALSE; 139 | } 140 | else 141 | { 142 | 143 | /* check for literal escape */ 144 | if (*p == '\\') 145 | p++; 146 | 147 | /* if end of pattern here 148 | then bad pattern */ 149 | if (!*p++) 150 | { 151 | *error_type = PATTERN_ESC; 152 | return FALSE; 153 | } 154 | } 155 | } 156 | } 157 | break; 158 | 159 | /* all other characters are valid pattern elements */ 160 | case '*': 161 | case '?': 162 | default: 163 | p++; /* "normal" character */ 164 | break; 165 | } 166 | } 167 | return TRUE; 168 | } 169 | 170 | 171 | /*---------------------------------------------------------------------------- 172 | * 173 | * Match the pattern PATTERN against the string TEXT; 174 | * 175 | * returns MATCH_VALID if pattern matches, or an errorcode as follows 176 | * otherwise: 177 | * 178 | * MATCH_PATTERN - bad pattern 179 | * MATCH_LITERAL - match failure on literal mismatch 180 | * MATCH_RANGE - match failure on [..] construct 181 | * MATCH_ABORT - premature end of text string 182 | * MATCH_END - premature end of pattern string 183 | * MATCH_VALID - valid match 184 | * 185 | * 186 | * A match means the entire string TEXT is used up in matching. 187 | * 188 | * In the pattern string: 189 | * `*' matches any sequence of characters (zero or more) 190 | * `?' matches any character 191 | * [SET] matches any character in the specified set, 192 | * [!SET] or [^SET] matches any character not in the specified set. 193 | * 194 | * A set is composed of characters or ranges; a range looks like 195 | * character hyphen character (as in 0-9 or A-Z). [0-9a-zA-Z_] is the 196 | * minimal set of characters allowed in the [..] pattern construct. 197 | * Other characters are allowed (ie. 8 bit characters) if your system 198 | * will support them. 199 | * 200 | * To suppress the special syntactic significance of any of `[]*?!^-\', 201 | * and match the character exactly, precede it with a `\'. 202 | * 203 | ----------------------------------------------------------------------------*/ 204 | 205 | int matche (register char *p, register char *t, MYBOOL case_sensitive) 206 | { 207 | register char range_start, range_end; /* start and end in range */ 208 | 209 | MYBOOL invert; /* is this [..] or [!..] */ 210 | MYBOOL member_match; /* have I matched the [..] construct? */ 211 | MYBOOL loop; /* should I terminate? */ 212 | 213 | for ( ; *p; p++, t++) 214 | { 215 | /* if this is the end of the text 216 | then this is the end of the match */ 217 | 218 | if (!*t) 219 | { 220 | return ( *p == '*' && *++p == '\0' ) ? 221 | MATCH_VALID : MATCH_ABORT; 222 | } 223 | 224 | /* determine and react to pattern type */ 225 | 226 | switch (*p) 227 | { 228 | case '?': /* single any character match */ 229 | break; 230 | 231 | case '*': /* multiple any character match */ 232 | return matche_after_star (p, t, case_sensitive); 233 | 234 | /* [..] construct, single member/exclusion character match */ 235 | case '[': 236 | { 237 | /* move to beginning of range */ 238 | 239 | p++; 240 | 241 | /* check if this is a member match or exclusion match */ 242 | 243 | invert = FALSE; 244 | if (*p == '!' || *p == '^') 245 | { 246 | invert = TRUE; 247 | p++; 248 | } 249 | 250 | /* if closing bracket here or at range start then we have a 251 | malformed pattern */ 252 | 253 | if (*p == ']') 254 | { 255 | return MATCH_PATTERN; 256 | } 257 | 258 | member_match = FALSE; 259 | loop = TRUE; 260 | 261 | while (loop) 262 | { 263 | /* if end of construct then loop is done */ 264 | 265 | if (*p == ']') 266 | { 267 | loop = FALSE; 268 | continue; 269 | } 270 | 271 | /* matching a '!', '^', '-', '\' or a ']' */ 272 | 273 | if (*p == '\\') 274 | { 275 | range_start = range_end = *++p; 276 | } 277 | else range_start = range_end = *p; 278 | 279 | /* if end of pattern then bad pattern (Missing ']') */ 280 | 281 | if (!*p) 282 | return MATCH_PATTERN; 283 | 284 | /* check for range bar */ 285 | if (*++p == '-') 286 | { 287 | /* get the range end */ 288 | 289 | range_end = *++p; 290 | 291 | /* if end of pattern or construct 292 | then bad pattern */ 293 | 294 | if (range_end == '\0' || range_end == ']') 295 | return MATCH_PATTERN; 296 | 297 | /* special character range end */ 298 | if (range_end == '\\') 299 | { 300 | range_end = *++p; 301 | 302 | /* if end of text then 303 | we have a bad pattern */ 304 | if (!range_end) 305 | return MATCH_PATTERN; 306 | } 307 | 308 | /* move just beyond this range */ 309 | p++; 310 | } 311 | 312 | /* if the text character is in range then match found. 313 | make sure the range letters have the proper 314 | relationship to one another before comparison */ 315 | 316 | if (range_start < range_end) 317 | { 318 | if (*t >= range_start && *t <= range_end) 319 | { 320 | member_match = TRUE; 321 | loop = FALSE; 322 | } 323 | } 324 | else 325 | { 326 | if (*t >= range_end && *t <= range_start) 327 | { 328 | member_match = TRUE; 329 | loop = FALSE; 330 | } 331 | } 332 | } 333 | 334 | /* if there was a match in an exclusion set then no match */ 335 | /* if there was no match in a member set then no match */ 336 | 337 | if ((invert && member_match) || !(invert || member_match)) 338 | return MATCH_RANGE; 339 | 340 | /* if this is not an exclusion then skip the rest of 341 | the [...] construct that already matched. */ 342 | 343 | if (member_match) 344 | { 345 | while (*p != ']') 346 | { 347 | /* bad pattern (Missing ']') */ 348 | if (!*p) 349 | return MATCH_PATTERN; 350 | 351 | /* skip exact match */ 352 | if (*p == '\\') 353 | { 354 | p++; 355 | 356 | /* if end of text then 357 | we have a bad pattern */ 358 | 359 | if (!*p) 360 | return MATCH_PATTERN; 361 | } 362 | 363 | /* move to next pattern char */ 364 | 365 | p++; 366 | } 367 | } 368 | break; 369 | } 370 | case '\\': /* next character is quoted and must match exactly */ 371 | 372 | /* move pattern pointer to quoted char and fall through */ 373 | 374 | p++; 375 | 376 | /* if end of text then we have a bad pattern */ 377 | 378 | if (!*p) 379 | return MATCH_PATTERN; 380 | 381 | /* must match this character exactly */ 382 | 383 | default: 384 | if (case_sensitive) { 385 | if (*p != *t) 386 | return MATCH_LITERAL; 387 | } 388 | else { 389 | if (toupper(*p) != toupper(*t)) 390 | return MATCH_LITERAL; 391 | } 392 | } 393 | } 394 | /* if end of text not reached then the pattern fails */ 395 | 396 | if (*t) 397 | return MATCH_END; 398 | else return MATCH_VALID; 399 | } 400 | 401 | 402 | /*---------------------------------------------------------------------------- 403 | * 404 | * recursively call matche() with final segment of PATTERN and of TEXT. 405 | * 406 | ----------------------------------------------------------------------------*/ 407 | 408 | int matche_after_star (register char *p, register char *t, MYBOOL case_sensitive) 409 | { 410 | register int match = 0; 411 | register int nextp; 412 | 413 | /* pass over existing ? and * in pattern */ 414 | 415 | while ( *p == '?' || *p == '*' ) 416 | { 417 | /* take one char for each ? and + */ 418 | 419 | if (*p == '?') 420 | { 421 | /* if end of text then no match */ 422 | if (!*t++) 423 | return MATCH_ABORT; 424 | } 425 | 426 | /* move to next char in pattern */ 427 | 428 | p++; 429 | } 430 | 431 | /* if end of pattern we have matched regardless of text left */ 432 | 433 | if (!*p) 434 | return MATCH_VALID; 435 | 436 | /* get the next character to match which must be a literal or '[' */ 437 | 438 | nextp = *p; 439 | if (nextp == '\\') 440 | { 441 | nextp = p[1]; 442 | 443 | /* if end of text then we have a bad pattern */ 444 | 445 | if (!nextp) 446 | return MATCH_PATTERN; 447 | } 448 | 449 | /* Continue until we run out of text or definite result seen */ 450 | 451 | do 452 | { 453 | /* a precondition for matching is that the next character 454 | in the pattern match the next character in the text or that 455 | the next pattern char is the beginning of a range. Increment 456 | text pointer as we go here */ 457 | 458 | /* if (nextp == *t || nextp == '[') */ 459 | if ((case_sensitive ? nextp == *t : toupper(nextp) == toupper(*t)) || nextp == '[') 460 | match = matche(p, t, case_sensitive); 461 | 462 | /* if the end of text is reached then no match */ 463 | 464 | if (!*t++) 465 | match = MATCH_ABORT; 466 | 467 | } while ( match != MATCH_VALID && 468 | match != MATCH_ABORT && 469 | match != MATCH_PATTERN); 470 | 471 | /* return result */ 472 | 473 | return match; 474 | } 475 | 476 | 477 | /*---------------------------------------------------------------------------- 478 | * 479 | * match() is a shell to matche() to return only MYBOOL values. 480 | * 481 | ----------------------------------------------------------------------------*/ 482 | 483 | MYBOOL match( char *p, char *t, MYBOOL case_sensitive ) 484 | { 485 | int error_type; 486 | 487 | error_type = matche(p,t,case_sensitive); 488 | return (error_type == MATCH_VALID ) ? TRUE : FALSE; 489 | } 490 | 491 | 492 | #ifdef TEST 493 | 494 | /* 495 | ** This test main expects as first arg the pattern and as second arg 496 | ** the match string. Output is yaeh or nay on match. If nay on 497 | ** match then the error code is parsed and written. 498 | */ 499 | 500 | #include 501 | 502 | int main(int argc, char *argv[]) 503 | { 504 | int error; 505 | int is_valid_error; 506 | 507 | if (argc != 3) 508 | printf("Usage: MATCH Pattern Text\n"); 509 | else 510 | { 511 | printf("Pattern: %s\n", argv[1]); 512 | printf("Text : %s\n", argv[2]); 513 | 514 | if (!is_pattern(argv[1])) 515 | printf(" First Argument Is Not A Pattern\n"); 516 | else 517 | { 518 | error = matche(argv[1],argv[2]); 519 | is_valid_pattern(argv[1],&is_valid_error); 520 | 521 | switch (error) 522 | { 523 | case MATCH_VALID: 524 | printf(" Match Successful"); 525 | if (is_valid_error != PATTERN_VALID) 526 | printf(" -- is_valid_pattern() " 527 | "is complaining\n"); 528 | else printf("\n"); 529 | break; 530 | 531 | case MATCH_LITERAL: 532 | printf(" Match Failed on Literal\n"); 533 | break; 534 | 535 | case MATCH_RANGE: 536 | printf(" Match Failed on [..]\n"); 537 | break; 538 | 539 | case MATCH_ABORT: 540 | printf(" Match Failed on Early " 541 | "Text Termination\n"); 542 | break; 543 | 544 | case MATCH_END: 545 | printf(" Match Failed on Early " 546 | "Pattern Termination\n"); 547 | break; 548 | 549 | case MATCH_PATTERN: 550 | switch (is_valid_error) 551 | { 552 | case PATTERN_VALID: 553 | printf(" Internal Disagreement " 554 | "On Pattern\n"); 555 | break; 556 | 557 | case PATTERN_ESC: 558 | printf(" Literal Escape at " 559 | "End of Pattern\n"); 560 | break; 561 | 562 | 563 | case PATTERN_RANGE: 564 | printf(" No End of Range in " 565 | "[..] Construct\n"); 566 | break; 567 | 568 | case PATTERN_CLOSE: 569 | printf(" [..] Construct is Open\n"); 570 | break; 571 | 572 | case PATTERN_EMPTY: 573 | printf(" [..] Construct is Empty\n"); 574 | break; 575 | 576 | default: 577 | printf(" Internal Error in " 578 | "is_valid_pattern()\n"); 579 | } 580 | break; 581 | 582 | default: 583 | printf(" Internal Error in matche()\n"); 584 | break; 585 | } 586 | } 587 | } 588 | return(0); 589 | } 590 | 591 | #endif 592 | -------------------------------------------------------------------------------- /src/parftpcl.c: -------------------------------------------------------------------------------- 1 | /* Routines for PARCP FTP-like command line client */ 2 | 3 | #if defined(_WIN32) || defined(__MSDOS__) /* Unix doesn't know getch() while DJGPP does */ 4 | # undef getch 5 | # if defined(_WIN32) && !defined(SHELL) 6 | # include 7 | # define get_key() _getch() 8 | # else 9 | # define get_key() getch() 10 | # endif 11 | 12 | #else 13 | 14 | #include 15 | 16 | int get_key() 17 | { 18 | BYTE key=0; 19 | #ifndef TIOCGETP /* Linux uses POSIX */ 20 | struct termios oldt, newt; 21 | 22 | tcgetattr(0, &oldt); 23 | newt = oldt; 24 | newt.c_lflag &= ~(ICANON|ECHO); /* don't echo, return immediately */ 25 | tcsetattr(0,TCSANOW, &newt); /* setup the keyboard */ 26 | int ret = read(0,&key,1); /* read key */ 27 | ret = ret; // UNUSED 28 | tcsetattr(0,TCSANOW, &oldt); /* restore the keyboard */ 29 | 30 | #else /* MiNT builds on BSD and uses sgtty */ 31 | 32 | struct sgttyb oldt, newt; 33 | int ret; 34 | 35 | ioctl(0,TIOCGETP,&oldt); 36 | newt = oldt; 37 | newt.sg_flags &= ~(ICANON|ECHO|CBREAK);/* don't echo, return immediately, watch out for the ^C */ 38 | ioctl(0,TIOCSETP,&newt); /* setup the keyboard */ 39 | ret = read(0,&key,1); /* read key */ 40 | ioctl(0,TIOCSETP,&oldt); /* restore the keyboard */ 41 | #endif 42 | 43 | return key; 44 | } 45 | #endif /* _WIN32 || __MSDOS__ */ 46 | /*******************************************************************************/ 47 | 48 | int q_overwrite(const char *name) 49 | { 50 | int ans; 51 | 52 | if (bInBatchMode) { 53 | ans = 1; /* SKIP ==> default answer in unattended mode */ 54 | } 55 | else { 56 | #ifdef SHELL 57 | if (shell && curses_initialized) { 58 | ans = shell_q_overwrite(name); 59 | } 60 | else 61 | #endif 62 | { 63 | printf("File '%s' already exists - Overwrite/Skip/Quit? [O/s/q]", name); 64 | switch(toupper(get_key())) { 65 | case 'S': 66 | ans=1; 67 | printf(" SKIP\n"); /* on the screen the "SKIP" info remains */ 68 | break; 69 | 70 | case 'O': 71 | case '\r': 72 | case '\n': 73 | ans=2; 74 | printf("\r \r"); 75 | break; 76 | 77 | default: 78 | ans = 0; 79 | printf(" QUIT\n"); 80 | } 81 | } 82 | } 83 | 84 | return ans; 85 | } 86 | 87 | /*******************************************************************************/ 88 | 89 | char *str_err(int status) 90 | { 91 | switch(status) { 92 | case INTERRUPT_TRANSFER: 93 | return "File transfer was stopped"; 94 | case FILE_SKIPPED: 95 | return "File skipped"; 96 | case ERROR_CRC_FAILED: 97 | return "CRC failed - file not transferred correctly"; 98 | case ERROR_READING_FILE: 99 | return "Error while reading file"; 100 | case ERROR_WRITING_FILE: 101 | return "Error while writing file - disk read-only or full?"; 102 | case ERROR_DELETING_FILE: 103 | return "Error deleting file - check if it's not read-only"; 104 | case ERROR_CREATING_DIRECTORY: 105 | return "Error creating directory"; 106 | default: 107 | { 108 | static char tmptxt[16]; 109 | sprintf(tmptxt, "Error #%d", status); 110 | return tmptxt; 111 | } 112 | } 113 | } 114 | 115 | int q_bugreport(int status) 116 | { 117 | int ans = 1; /* IGNORE ==> default answer in unattended mode */ 118 | 119 | if (status == QUIT_TRANSFER) 120 | return 0; /* Abort */ 121 | 122 | if (!status || status == FILE_SKIPPED) 123 | return ans; 124 | 125 | if (bInBatchMode) { 126 | return ans; 127 | } 128 | else { 129 | char *err_txt = str_err(status); 130 | 131 | #ifdef SHELL 132 | if (shell && curses_initialized) { 133 | ans = shell_q_bugreport(err_txt); 134 | } 135 | else 136 | #endif 137 | { 138 | printf("%s - Retry/Ignore/Abort? [R/i/a]", err_txt); 139 | switch(toupper(get_key())) { 140 | case 'I': /* Ignore */ 141 | ans=1; 142 | printf(" Ignore\n"); 143 | break; 144 | 145 | case 'R': /* Retry */ 146 | case '\r': 147 | case '\n': 148 | ans=2; 149 | printf("\r \r"); 150 | break; 151 | 152 | default: /* Abort */ 153 | ans = 0; 154 | printf(" Abort\n"); 155 | } 156 | } 157 | } 158 | 159 | return ans; 160 | } 161 | 162 | #include "sort.c" 163 | 164 | int real_delka_jmena(const char *jmeno, int min_delka) 165 | { 166 | int j, real_delka = 0; 167 | 168 | for(j=min_delka; j= DIRLINELEN) { 214 | if ( (x = real_delka_jmena(t, 0)) > maxdel) 215 | maxdel = x; 216 | 217 | t+=DIRLINELEN; 218 | } 219 | if (maxdel > maximalne) 220 | maxdel = maximalne; 221 | 222 | DPRINT1(" maxdel = %d\n", maxdel); 223 | } 224 | 225 | radek = odchod = 0; 226 | 227 | while(!odchod) { 228 | int sloup=0, c = *s; 229 | 230 | if (is_dir && strlen(s) >= DIRLINELEN) { 231 | char *pradek; 232 | 233 | pradek = orez_jmeno(s, maxdel); 234 | strncpy(pradek+maxdel, s+MAXFNAME, DIRLINELEN-MAXFNAME); 235 | pradek[maxdel + DIRLINELEN-MAXFNAME] = 0; 236 | printf("%s", pradek); 237 | s+=DIRLINELEN; 238 | } 239 | else { 240 | while((c = *s++) && ++sloup 0 && radek >= (page_length-2)) { 250 | int key; 251 | 252 | printf("..... more ..... [Return/Space/q]"); 253 | key = get_key(); 254 | printf("\r \r"); 255 | switch(key) { 256 | case 'q' : odchod = 1; break; 257 | case '\r': 258 | case '\n': radek = page_length-2; break; /* display one line */ 259 | case ' ' : 260 | default : radek = 0; break; /* display whole page */ 261 | } 262 | } 263 | } 264 | } 265 | 266 | /*******************************************************************************/ 267 | 268 | void normalize_over_switches(void) 269 | { 270 | _over_older = toupper(_over_older); 271 | if (_over_older != 'S' && _over_older != 'R') 272 | _over_older = 'A'; 273 | 274 | _over_newer = toupper(_over_newer); 275 | if (_over_newer != 'S' && _over_newer != 'R') 276 | _over_newer = 'A'; 277 | } 278 | 279 | void print_status(int co) 280 | { 281 | #define ONOFF(a) a?"YES":"NO" 282 | 283 | if (!co) 284 | puts("Version "VERZE" (compiled on "__DATE__")\n"); 285 | if (!co || co == 1) 286 | printf("Hash mark: %s (block size is %ld kB)\n", ONOFF(hash_mark), buffer_len/KILO); 287 | if (!co || co == 2) 288 | printf("Upper/lower-case sensitive matching of filenames: %s\n", ONOFF(_case_sensitive)); 289 | if (!co || co == 13) 290 | printf("Preserve DOS Filename Case: %s\n", ONOFF(_preserve_case)); 291 | if (!co || co == 10) 292 | printf("Show hidden files: %s\n", ONOFF(_show_hidden)); 293 | if (!co || co == 3) 294 | printf("Existing older files: %s\n", _over_older == 'S' ? "Skip" : _over_older == 'R' ? "Replace" : "Ask"); 295 | if (!co || co == 9) 296 | printf("Existing newer files: %s\n", _over_newer == 'S' ? "Skip" : _over_newer == 'R' ? "Replace" : "Ask"); 297 | if (!co || co == 4) 298 | printf("Sending whole subdirectory trees: %s\n", ONOFF(_send_subdir)); 299 | if (!co || co == 5) 300 | printf("Keep timestamp of copied files: %s\n", ONOFF(_keep_timestamp)); 301 | if (!co || co == 11) 302 | printf("Keep attributes of copied files: %s\n", ONOFF(_keep_attribs)); 303 | if (!co || co == 12) 304 | printf("Archive mode: %s\n", ONOFF(_archive_mode)); 305 | if (!co || co == 8) 306 | printf("CRC (check sum) of every copied block: %s\n", ONOFF(_checksum)); 307 | if (!co || co == 6) 308 | printf("Page length is %d lines\n", page_length); 309 | if (!co || co == 7) { 310 | char how[MAXSTRING]=""; 311 | 312 | if (_sort_case) 313 | strcat(how, "Case sensitive "); 314 | 315 | if (_sort_jak == tolower(_sort_jak)) 316 | strcat(how, "Descending "); 317 | 318 | strcat(how, "Sorting by file "); 319 | switch(toupper(_sort_jak)) { 320 | case 'N': strcat(how, "name\n"); break; 321 | case 'E': strcat(how, "extension\n"); break; 322 | case 'S': strcat(how, "size\n"); break; 323 | case 'D': strcat(how, "date & time\n"); break; 324 | default: strcpy(how, "Dir listing is unsorted\n"); 325 | } 326 | printf("%s", how); 327 | } 328 | puts(""); 329 | } 330 | 331 | MYBOOL do_client(int coming_from_shell, FILE *input_commands) 332 | { 333 | #define IS_ON(a) (!strcasecmp(a, "ON") || !strcasecmp(a, "YES")) 334 | 335 | if (input_commands == NULL) 336 | input_commands = stdin; 337 | 338 | bInBatchMode = (input_commands != stdin); 339 | 340 | if (bInBatchMode) { 341 | puts("\nPARCP file transfer client in batch mode:\n"); 342 | } 343 | else { 344 | puts("\n File transfer client\n"); 345 | print_status(0); /* display switches setting */ 346 | printf("Client machine: %s\n", local_machine); 347 | printf("Server machine: %s\n\n", remote_machine); 348 | } 349 | 350 | #ifdef SHELL 351 | if (coming_from_shell) { 352 | shell = FALSE; /* disable shell! */ 353 | puts("Type EXIT to return back to ParShell\n"); 354 | } 355 | #endif 356 | 357 | g_last_status = 0; 358 | while(1) { 359 | static char b[MAXSTRING]; 360 | char *p1, *p2, *ret; 361 | 362 | if (bInBatchMode && feof(input_commands)) { /* end of AUTOEXEC script */ 363 | bInBatchMode = FALSE; 364 | return TRUE; 365 | } 366 | 367 | if (! bInBatchMode) 368 | printf(">>"); 369 | ret = fgets(b, sizeof(b), input_commands); 370 | ret = ret; // UNUSED 371 | 372 | p1 = strtok(b, " \n"); 373 | if (p1 == NULL) continue; 374 | p2 = strtok(NULL, "\n"); 375 | 376 | if (!strcasecmp(p1, "QUIT") || !strcasecmp(p1, "LQUIT") || !strcasecmp(p1, "BYE")) { 377 | if (! coming_from_shell) { 378 | write_word( toupper(p1[0]) == 'L' ? M_LQUIT : M_QUIT ); 379 | bInBatchMode = FALSE; 380 | return FALSE; 381 | } 382 | #ifdef SHELL 383 | else 384 | puts("Type EXIT instead"); 385 | } 386 | 387 | else if (!strcasecmp(p1, "EXIT")) { 388 | if (coming_from_shell) { 389 | g_last_status = 0; 390 | shell = TRUE; /* enable shell! */ 391 | bInBatchMode = FALSE; 392 | return TRUE; 393 | } 394 | else 395 | puts("ParShell not available"); 396 | #endif 397 | } 398 | 399 | else if(!strcasecmp(p1, "PWD")) { /* print server current dir */ 400 | write_word(M_PWD); 401 | receive_string(string_buffer); 402 | puts((char *)string_buffer); 403 | } 404 | 405 | else if(!strcasecmp(p1, "LPWD")) { /* local current directory */ 406 | get_cwd(b, MAXSTRING); 407 | puts(b); 408 | } 409 | 410 | else if (!strcasecmp(p1, "CD")) { /* chg dir on server */ 411 | if (p2 == NULL) { 412 | puts("ERROR: no directory given"); 413 | continue; 414 | } 415 | write_word(M_CD); 416 | send_string(p2); 417 | if (read_word() == M_OK) 418 | printf("Directory on server is now "); 419 | receive_string(string_buffer); 420 | puts((char *)string_buffer); 421 | } 422 | 423 | else if(!strcasecmp(p1, "LCD")) { /* local change dir */ 424 | if (p2 == NULL) { 425 | puts("ERROR: no directory given"); 426 | continue; 427 | } 428 | if (change_dir(p2, string_buffer)) 429 | printf("Local directory is now "); 430 | puts((char *)string_buffer); 431 | } 432 | 433 | else if (!strcasecmp(p1, "MD") || !strcasecmp(p1, "MKDIR")) { /* make dir on server */ 434 | if (p2 == NULL) { 435 | puts("ERROR: no directory given"); 436 | continue; 437 | } 438 | write_word(M_MD); 439 | send_string(p2); 440 | puts( (read_word() == M_OK) ? "OK" : "CAN'T CREATE DIRECTORY"); 441 | } 442 | 443 | else if (!strcasecmp(p1, "LMD") || !strcasecmp(p1, "LMKDIR")) { /* make dir on client */ 444 | if (p2 == NULL) { 445 | puts("ERROR: no directory given"); 446 | continue; 447 | } 448 | puts( (mkdir(p2) == 0) ? "OK" : "CAN'T CREATE DIRECTORY"); 449 | } 450 | 451 | else if (!strcasecmp(p1, "DIR") || !strcasecmp(p1, "LS") /* dir listing on server */ 452 | || !strcasecmp(p1, "LDIR") || !strcasecmp(p1, "LLS")) {/* display local dir */ 453 | MYBOOL local = (toupper(*p1) == 'L'); 454 | UWORD maska = 0; 455 | 456 | if (p2 == NULL) 457 | p2 = ""; 458 | else if (*p2 == '-') { 459 | char *p3 = strtok(p2, " \n"); 460 | p2 = strtok(NULL, "\n"); 461 | if (p2 == NULL) 462 | p2 = ""; 463 | /* additional parameters */ 464 | while(*(++p3)) { 465 | if (*p3 == 'd') 466 | maska |= LS_DIRS_ONLY; 467 | if (*p3 == 'f') 468 | maska |= LS_FILES_ONLY; 469 | if (*p3 == 'n') 470 | maska |= LS_NEGATE_MASK; 471 | } 472 | } 473 | 474 | if (! local) { 475 | write_word(M_DIR); 476 | send_string(p2); 477 | write_word(maska); 478 | wait_before_read(); 479 | receive_string(dir_buffer); 480 | } 481 | else { 482 | list_dir(p2, maska, dir_buffer); 483 | } 484 | setridit_list_dir(dir_buffer); 485 | view(dir_buffer, TRUE); 486 | } 487 | 488 | else if (!strcasecmp(p1, "DRV")) { /* listing of server's drives */ 489 | write_word(M_DRV); 490 | wait_before_read(); 491 | receive_string(dir_buffer); 492 | view(dir_buffer, TRUE); 493 | } 494 | 495 | else if(!strcasecmp(p1, "LDRV")) { /* display local drives */ 496 | list_drives(dir_buffer); 497 | view(dir_buffer, TRUE); 498 | } 499 | 500 | else if (!strcasecmp(p1, "PUT") || !strcasecmp(p1, "PUTDEL") /* PUT(DEL) file to server */ 501 | || !strcasecmp(p1, "GET") || !strcasecmp(p1, "GETDEL")) { /* GET(DEL) file from server */ 502 | MYBOOL sending = strncasecmp(p1, "PUT", 3) == 0 ? TRUE : FALSE; 503 | 504 | if (p2 == NULL) { /* local file name */ 505 | puts("ERROR: no file name"); 506 | continue; 507 | } 508 | 509 | if (_check_info) { 510 | get_files_info(sending, p2, TRUE); 511 | 512 | if (!g_files && !g_folders) { 513 | printf("ERROR: '%s' file(s) not found.\n", p2); 514 | g_last_status = FILE_NOTFOUND; 515 | continue; 516 | } 517 | if (! _quiet_mode) { 518 | char buf_size[MAXSTRING]; 519 | show_size64(buf_size, g_bytes); 520 | printf("%s %lu files in %lu folders (total size %s)\n", 521 | sending ? "Sending" : "Receiving", g_files, g_folders,buf_size); 522 | } 523 | send_collected_info(); 524 | } 525 | 526 | g_last_status = copy_files(sending, p2, (strncasecmp(p1+3, "DEL", 3) == 0)); 527 | } 528 | 529 | else if (!strcasecmp(p1, "DEL") || !strcasecmp(p1, "LDEL") 530 | || !strcasecmp(p1, "RM") || !strcasecmp(p1, "LRM")) { 531 | MYBOOL local = (toupper(*p1) == 'L'); 532 | 533 | if (p2 == NULL) { /* local file name */ 534 | puts("ERROR: no file name"); 535 | continue; 536 | } 537 | 538 | if (_check_info) { 539 | get_files_info(local, p2, FALSE); /* FALSE = do not respect _archive_mode */ 540 | 541 | if (!g_files && !g_folders) { 542 | printf("ERROR: '%s' file(s) not found.\n", p2); 543 | g_last_status = FILE_NOTFOUND; 544 | continue; 545 | } 546 | if (! _quiet_mode) { 547 | char buf_size[MAXSTRING]; 548 | show_size64(buf_size, g_bytes); 549 | printf("Deleting %ld files in %ld folders (total size %s)\n", 550 | g_files, g_folders, buf_size); 551 | } 552 | } 553 | 554 | g_last_status = delete_files(local, p2); 555 | 556 | puts( g_last_status ? "CAN'T DELETE FILE" : "OK" ); 557 | } 558 | 559 | else if (!strcasecmp(p1, "REN") || !strcasecmp(p1, "LREN")) { 560 | char c[MAXFNAME+1], *p3, *ret; 561 | 562 | if (p2 == NULL) { /* local file name */ 563 | puts("ERROR: no file name"); 564 | continue; 565 | } 566 | if (is_pattern(p2)) { 567 | puts("ERROR: wildcards not allowed"); 568 | continue; 569 | } 570 | 571 | printf("New name: "); 572 | ret = fgets(c, (int)sizeof(c), input_commands); 573 | ret = ret; // UNUSED 574 | p3 = strtok(c, "\n"); 575 | if (!p3 || !*p3) { 576 | puts("ERROR: no new file name"); 577 | continue; 578 | } 579 | 580 | if (toupper(*p1) != 'L') { /* REN */ 581 | write_word(M_REN); 582 | send_string(p2); 583 | send_string(p3); 584 | g_last_status = read_word() ? FILE_NOTFOUND : 0; 585 | } 586 | else /* LREN */ 587 | g_last_status = rename(p2, p3) ? FILE_NOTFOUND : 0; 588 | 589 | puts( g_last_status ? "CAN'T RENAME FILE" : "OK" ); 590 | } 591 | 592 | else if (HAS_CMD_EXEC && (!strcasecmp(p1, "EXEC") || !strcasecmp(p1, "LEXEC"))) { 593 | MYBOOL wait = TRUE; 594 | 595 | if (p2 == NULL) { /* local file name */ 596 | puts("ERROR: no program name"); 597 | continue; 598 | } 599 | 600 | if (*p2 == '-') { 601 | char *p3 = strtok(p2, " \n"); 602 | p2 = strtok(NULL, "\n"); 603 | if (p2 == NULL) { 604 | puts("ERROR: no program name"); 605 | continue; 606 | } 607 | /* additional parameters */ 608 | if (p3[1] == 'n') 609 | wait = FALSE; 610 | } 611 | 612 | if (toupper(*p1) != 'L') { /* EXEC */ 613 | write_word(wait ? M_EXEC : M_EXECNOWAIT); 614 | send_string(p2); 615 | if (wait) { 616 | wait_before_read(); 617 | g_last_status = read_word() ? FILE_NOTFOUND : 0; 618 | } 619 | else { 620 | g_last_status = 0; 621 | } 622 | } 623 | else { /* LEXEC */ 624 | g_last_status = system(p2) ? FILE_NOTFOUND : 0; 625 | } 626 | 627 | puts( g_last_status ? "CAN'T EXEC FILE OR RETURN CODE IS NONZERO" : "OK" ); 628 | } 629 | 630 | else if (!strcasecmp(p1, "GETTIME")) { 631 | write_word(M_GETTIME); 632 | g_last_status = ReceiveDataAndSetLocalTime(); 633 | } 634 | 635 | else if (!strcasecmp(p1, "PUTTIME")) { 636 | write_word(M_PUTTIME); 637 | g_last_status = GetLocalTimeAndSendItOver(); 638 | } 639 | 640 | else if (!strcasecmp(p1, "SHOWTIME")) { 641 | time_t time_now = time(NULL); 642 | printf("Client's time is %s", ctime(&time_now)); 643 | write_word(M_GETTIME); 644 | time_now = read_long(); 645 | printf("Server's time is %s", asctime(gmtime(&time_now))); 646 | } 647 | 648 | else if (!strcasecmp(p1, "HASH")) { 649 | if (p2 != NULL) 650 | hash_mark = IS_ON(p2) ? TRUE : FALSE; 651 | else 652 | hash_mark = !hash_mark; 653 | 654 | print_status(1); 655 | } 656 | 657 | else if (!strcasecmp(p1, "CASE")) { 658 | if (p2 != NULL) 659 | _case_sensitive = IS_ON(p2) ? TRUE : FALSE; 660 | else 661 | _case_sensitive = !_case_sensitive; 662 | 663 | send_parameters(); 664 | print_status(2); 665 | } 666 | 667 | else if (!strcasecmp(p1, "DOSCASE")) { 668 | if (p2 != NULL) 669 | _preserve_case = IS_ON(p2) ? TRUE : FALSE; 670 | else 671 | _preserve_case = !_preserve_case; 672 | 673 | send_parameters(); 674 | print_status(13); 675 | } 676 | 677 | else if (!strcasecmp(p1, "HIDDEN")) { 678 | if (p2 != NULL) 679 | _show_hidden = IS_ON(p2) ? TRUE : FALSE; 680 | else 681 | _show_hidden = !_show_hidden; 682 | 683 | send_parameters(); 684 | print_status(10); 685 | } 686 | 687 | else if (!strcasecmp(p1, "OVEROLD")) { 688 | if (p2 != NULL) { 689 | _over_older = toupper(*p2); 690 | normalize_over_switches(); 691 | send_parameters(); 692 | } 693 | print_status(3); 694 | } 695 | 696 | else if (!strcasecmp(p1, "OVERNEW")) { 697 | if (p2 != NULL) { 698 | _over_newer = toupper(*p2); 699 | normalize_over_switches(); 700 | send_parameters(); 701 | } 702 | print_status(9); 703 | } 704 | 705 | else if (!strcasecmp(p1, "SUBD")) { 706 | if (p2 != NULL) 707 | _send_subdir = IS_ON(p2) ? TRUE : FALSE; 708 | else 709 | _send_subdir = !_send_subdir; 710 | 711 | send_parameters(); 712 | print_status(4); 713 | } 714 | 715 | else if (!strcasecmp(p1, "KEEP")) { 716 | if (p2 != NULL) 717 | _keep_timestamp = IS_ON(p2) ? TRUE : FALSE; 718 | else 719 | _keep_timestamp = !_keep_timestamp; 720 | 721 | send_parameters(); 722 | print_status(5); 723 | } 724 | 725 | else if (!strcasecmp(p1, "ATTRIB")) { 726 | if (p2 != NULL) 727 | _keep_attribs = IS_ON(p2) ? TRUE : FALSE; 728 | else 729 | _keep_attribs = !_keep_attribs; 730 | 731 | send_parameters(); 732 | print_status(11); 733 | } 734 | 735 | else if (!strcasecmp(p1, "ARCHIVE")) { 736 | if (p2 != NULL) 737 | _archive_mode = IS_ON(p2) ? TRUE : FALSE; 738 | else 739 | _archive_mode = !_archive_mode; 740 | 741 | send_parameters(); 742 | print_status(12); 743 | } 744 | 745 | else if (!strcasecmp(p1, "CRC")) { 746 | if (p2 != NULL) 747 | _checksum = IS_ON(p2) ? TRUE : FALSE; 748 | else 749 | _checksum = !_checksum; 750 | 751 | send_parameters(); 752 | print_status(8); 753 | } 754 | 755 | else if (!strcasecmp(p1, "PGLEN")) { 756 | if (p2 != NULL) 757 | page_length = atol(p2); 758 | 759 | print_status(6); 760 | } 761 | 762 | else if (!strcasecmp(p1, "SORT")) { 763 | if (p2 != NULL) 764 | _sort_jak = *p2; 765 | 766 | print_status(7); 767 | } 768 | 769 | else if (!strcasecmp(p1, "SORTCASE")) { 770 | if (p2 != NULL) 771 | _sort_case = IS_ON(p2) ? TRUE : FALSE; 772 | else 773 | _sort_case = !_sort_case; 774 | 775 | print_status(7); 776 | } 777 | 778 | else if (!strcasecmp(p1, "STAT")) 779 | print_status(0); 780 | 781 | else if (!strcasecmp(p1, "SAVE")) 782 | config_file(cfg_fname, TRUE); 783 | 784 | else if (!strcasecmp(p1, "HELP")) { 785 | char *PARCP_HELP = "\n PARCP commands:\n\n" 786 | "QUIT quit both Client and Server (AKA bye)\n" 787 | "LQUIT quit only Client, Server wait for another session\n" 788 | #ifdef SHELL 789 | "EXIT go back to ParShell\n" 790 | #endif 791 | "\n" 792 | "PUT template send local files (from Client) to Server\n" 793 | "GET template receive files from Server to Client\n" 794 | "PUTDEL template just like PUT, but delete sent files on Client\n" 795 | "GETDEL template just like GET, but delete received files on Server\n" 796 | "DIR [-fdn] [templ] display file list on Server (AKA ls)\n" 797 | "LDIR [-fdn] [templ] display local file list (AKA lls)\n" 798 | "DEL template delete files on Server (AKA rm)\n" 799 | "LDEL template delete local files (AKA lrm)\n" 800 | "REN filename rename file on Server\n" 801 | "LREN filename rename local file\n" 802 | "EXEC [-n] filename run program on Server (-n = no wait)\n" 803 | "LEXEC filename run program locally (on Client)\n" 804 | "GETTIME get Server's date/time and set it on Client\n" 805 | "PUTTIME send Client's local date/time and set it on Server\n" 806 | "SHOWTTIME show current date and time on both Client and Server\n" 807 | "\n" 808 | "PWD print current working directory on Server\n" 809 | "LPWD print current working directory on Client\n" 810 | "CD dir change directory on Server\n" 811 | "LCD dir change local directory (on Client)\n" 812 | "MD dir make directory on Server (AKA mkdir)\n" 813 | "LMD dir make directory on Client (AKA lmkdir)\n" 814 | "DRV display drives on Server\n" 815 | "LDRV display local drives\n" 816 | "\n" 817 | "HASH [ON/OFF] display hash marks (= dot per block)\n" 818 | "CASE [ON/OFF] upper/lower-case sensitive pattern matching\n" 819 | "DOSCASE [ON/OFF] preserve DOS Filename Case\n" 820 | "HIDDEN [ON/OFF] show hidden files on MS-DOS filesystem\n" 821 | "OVEROLD [SRA] replace or skip existing older files\n" 822 | "OVERNEW [SRA] replace or skip existing newer files\n" 823 | "SUBD [ON/OFF] sending whole subdirectory trees\n" 824 | "KEEP [ON/OFF] keeping timestamp of copied files\n" 825 | "ATTRIB [ON/OFF] keeping attributes of copied files\n" 826 | "ARCHIVE [ON/OFF] copy files in archive mode\n" 827 | "CRC [ON/OFF] do CRC (check sum) of every block\n" 828 | "PGLEN [number] length of view page\n" 829 | "SORT [NnEeSsDdU] sorting of dir listing by Name, Ext, Size, Date, Unsorted\n" 830 | "SORTCASE [ON/OFF] case sensitive sorting\n" 831 | "\n" 832 | "STAT display actual settings\n" 833 | "SAVE save actual settings into configuration file\n"; 834 | 835 | view(PARCP_HELP, FALSE); 836 | } 837 | 838 | else /* bad command */ 839 | printf("UNKNOWN COMMAND '%s'\n", p1); 840 | } 841 | } 842 | --------------------------------------------------------------------------------