Discussion:
need this C translated to pascal-family - please.
(too old to reply)
n***@gmail.com
2010-09-17 23:49:43 UTC
Permalink
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
I'll clean-up and integrate all contributions.

This code apparently:
reads the vendor, product ID provided by a USB device which
looks like a CDrom.
The zeroCD device is designed to down-load its driver to a
WinXYZ PC which runs the driver, which then switches the fake
CDrom over to a wireless-modem, which is then usable by the
PC which has d/l-ed the required driver from the fake CDrom.
I fear that my `Huawei 2252+` may not use any standard
protocol, since once it has d/l-ed its driver to the Win-PC,
they can communicate in their own private/secret language ?

/*
Mode switching tool for controlling flip flop (multiple device) USB gear
Version 1.1.4, 2010/08/17

Copyright (C) 2007, 2008, 2009, 2010 Josua Dietze
http://www.gnu.org/licenses/gpl.txt */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <ctype.h>
#include <getopt.h>
#include <syslog.h>

#include <usb.h>
#include "usb_modeswitch.h"
! various IMPORTs

#define LINE_DIM 1024
#define BUF_SIZE 4096
#define DESCR_MAX 129

#define SEARCH_DEFAULT 0
#define SEARCH_TARGET 1
! various CONSTs <------

#define SHOW_PROGRESS if (show_progress) printf

//int write_bulk(int endpoint, char *message, int length);
//int read_bulk(int endpoint, char *buffer, int length);

//int find_first_bulk_output_endpoint(struct usb_device *dev);
//int find_first_bulk_input_endpoint(struct usb_device *dev);

char *TempPP=NULL;

struct usb_device *dev;
struct usb_dev_handle *devh;
! is '*dev' a pointer to a RECORD called usb_device ?? <------

int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=0, TargetClass=0;
int MessageEndpoint=0, ResponseEndpoint=0, defaultClass=0, MessageDelay=0;
int targetDeviceCount=0;
int devnum=-1, busnum=-1;
int ret;

char DetachStorageOnly=0, HuaweiMode=0, SierraMode=0, SonyMode=0, GCTMode=0;
char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
char NeedResponse=0, NoDriverLoading=0, InquireDevice=1, sysmode=0;
! define several VARs & initialise some <------

char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];

char MessageContent[LINE_DIM];
char MessageContent2[LINE_DIM];
char MessageContent3[LINE_DIM];
char TargetProductList[LINE_DIM];
char ByteString[LINE_DIM/2];
char buffer[BUF_SIZE];
! define some char-ARRAYs <------

/* Settable Interface and Configuration (for debugging mostly) (jmw) */
int Interface = 0, Configuration = -1, AltSetting = -1;


static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'e'},
{"default-vendor", required_argument, 0, 'v'},
{"default-product", required_argument, 0, 'p'},
{"target-vendor", required_argument, 0, 'V'},
{"target-product", required_argument, 0, 'P'},
{"target-class", required_argument, 0, 'C'},
{"message-endpoint", required_argument, 0, 'm'},
{"message-content", required_argument, 0, 'M'},
{"message-content2", required_argument, 0, '2'},
{"message-content3", required_argument, 0, '3'},
{"message-delay", required_argument, 0, 'w'},
{"response-endpoint", required_argument, 0, 'r'},
{"detach-only", no_argument, 0, 'd'},
{"huawei-mode", no_argument, 0, 'H'},
{"sierra-mode", no_argument, 0, 'S'},
{"sony-mode", no_argument, 0, 'O'},
{"gct-mode", no_argument, 0, 'G'},
{"need-response", no_argument, 0, 'n'},
{"reset-usb", no_argument, 0, 'R'},
{"config-file", required_argument, 0, 'c'},
{"verbose", no_argument, 0, 'W'},
{"quiet", no_argument, 0, 'Q'},
{"sysmode", no_argument, 0, 'D'},
{"no-inquire", no_argument, 0, 'I'},
{"check-success", required_argument, 0, 's'},
{"interface", required_argument, 0, 'i'},
{"configuration", required_argument, 0, 'u'},
{"altsetting", required_argument, 0, 'a'},
{0, 0, 0, 0}
};
! is this a RECORD containing an ARRAY OF <strings>?

void readConfigFile(const char *configFilename)
{
if (verbose) printf("Reading config file: %s\n", configFilename);
ParseParamHex(configFilename, TargetVendor);
ParseParamHex(configFilename, TargetProduct);
ParseParamString(configFilename, TargetProductList);
ParseParamHex(configFilename, TargetClass);
ParseParamHex(configFilename, DefaultVendor);
ParseParamHex(configFilename, DefaultProduct);
ParseParamBool(configFilename, DetachStorageOnly);
ParseParamBool(configFilename, HuaweiMode);
ParseParamBool(configFilename, SierraMode);
ParseParamBool(configFilename, SonyMode);
ParseParamBool(configFilename, GCTMode);
ParseParamBool(configFilename, NoDriverLoading);
ParseParamHex(configFilename, MessageEndpoint);
ParseParamString(configFilename, MessageContent);
ParseParamString(configFilename, MessageContent2);
ParseParamString(configFilename, MessageContent3);
ParseParamInt(configFilename, MessageDelay);
ParseParamHex(configFilename, NeedResponse);
ParseParamHex(configFilename, ResponseEndpoint);
ParseParamHex(configFilename, ResetUSB);
ParseParamHex(configFilename, InquireDevice);
ParseParamInt(configFilename, CheckSuccess);
ParseParamHex(configFilename, Interface);
ParseParamHex(configFilename, Configuration);
ParseParamHex(configFilename, AltSetting);
! all the above PROC calls, initialies their 2nd arg, which is a global-var.
! configFilename is variably:
! but `readConfigFile` is only called from one place:
! readConfigFile(optarg)
! with ONE arg -- which doesn't match its declaration: of 2 args ?

/* TargetProductList has priority over TargetProduct */
if (strlen(TargetProductList))
{
TargetProduct = 0;
SHOW_PROGRESS("Warning: TargetProductList overrides TargetProduct!\n");
}

config_read = 1;
}
! end of PROC readConfigFile


void printConfig()
{
if ( DefaultVendor )
printf ("DefaultVendor= 0x%04x\n", DefaultVendor);
else
printf ("DefaultVendor= not set\n");
if ( DefaultProduct )
printf ("DefaultProduct= 0x%04x\n", DefaultProduct);
else
printf ("DefaultProduct= not set\n");
if ( TargetVendor )
printf ("TargetVendor= 0x%04x\n", TargetVendor);
else
printf ("TargetVendor= not set\n");
if ( TargetProduct )
printf ("TargetProduct= 0x%04x\n", TargetProduct);
else
printf ("TargetProduct= not set\n");
if ( TargetClass )
printf ("TargetClass= 0x%02x\n", TargetClass);
else
printf ("TargetClass= not set\n");
printf ("TargetProductList=\"%s\"\n", TargetProductList);
printf ("\nDetachStorageOnly=%i\n", (int)DetachStorageOnly);
printf ("HuaweiMode=%i\n", (int)HuaweiMode);
printf ("SierraMode=%i\n", (int)SierraMode);
printf ("SonyMode=%i\n", (int)SonyMode);
printf ("GCTMode=%i\n", (int)GCTMode);
if ( MessageEndpoint )
printf ("MessageEndpoint=0x%02x\n", MessageEndpoint);
else
printf ("MessageEndpoint= not set\n");
printf ("MessageContent=\"%s\"\n", MessageContent);
if ( strlen(MessageContent2) )
printf ("MessageContent2=\"%s\"\n", MessageContent2);
if ( strlen(MessageContent3) )
printf ("MessageContent3=\"%s\"\n", MessageContent3);
printf ("NeedResponse=%i\n", (int)NeedResponse);
if ( ResponseEndpoint )
printf ("ResponseEndpoint=0x%02x\n", ResponseEndpoint);
else
printf ("ResponseEndpoint= not set\n");
printf ("Interface=0x%02x\n", Interface);
if ( Configuration > -1 )
printf ("Configuration=0x%02x\n", Configuration);
if ( AltSetting > -1 )
printf ("AltSetting=0x%02x\n", AltSetting);
if ( InquireDevice )
printf ("\nInquireDevice enabled (default)\n");
else
printf ("\nInquireDevice disabled\n");
if ( CheckSuccess )
printf ("Success check enabled, max. wait time %d seconds\n", CheckSuccess);
else
printf ("Success check disabled\n");
if ( sysmode )
printf ("System integration mode enabled\n");
else
printf ("System integration mode disabled\n");
printf ("\n");
}
! end of PROC printConfig

int readArguments(int argc, char **argv)
{
int c, option_index = 0, count=0;
if (argc==1)
{
printHelp();
printVersion();
exit(1);
}

while (1)
{
c = getopt_long (argc, argv, "heWQDndHSOGRIv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:",
long_options, &option_index);

/* Detect the end of the options. */
if (c == -1)
break;
count++;
switch (c)
{
case 'R': ResetUSB = 1; break;
case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
case 'C': TargetClass = strtol(optarg, NULL, 16); break;
case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
case 'M': strcpy(MessageContent, optarg); break;
case '2': strcpy(MessageContent2, optarg); break;
case '3': strcpy(MessageContent3, optarg); break;
case 'w': MessageDelay = strtol(optarg, NULL, 10); count--; break;
case 'n': NeedResponse = 1; break;
case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
case 'd': DetachStorageOnly = 1; break;
case 'H': HuaweiMode = 1; break;
case 'S': SierraMode = 1; break;
case 'O': SonyMode = 1; break;
case 'G': GCTMode = 1; break;
case 'c': readConfigFile(optarg); break;
case 'W': verbose = 1; show_progress = 1; count--; break;
case 'Q': show_progress = 0; verbose = 0; count--; break;
case 'D': sysmode = 1; count--; break;
case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
case 'I': InquireDevice = 0; break;

case 'i': Interface = strtol(optarg, NULL, 16); break;
case 'u': Configuration = strtol(optarg, NULL, 16); break;
case 'a': AltSetting = strtol(optarg, NULL, 16); break;

case 'e':
printVersion();
exit(0);
break;
case 'h':
printVersion();
printHelp();
exit(0);
break;

default: /* Unsupported - error message has already been printed */
printf ("\n");
printHelp();
exit(1);
}
}

return count;
}

! end of PROC readArguments

int main(int argc, char **argv)
! main/top/entry-point 'block'
{
int numDefaults = 0, specialMode = 0, sonySuccess = 0;

/* Make sure we have empty strings even if not set by config */
TargetProductList[0] = '\0';
MessageContent[0] = '\0';
MessageContent2[0] = '\0';
MessageContent3[0] = '\0';


signal(SIGTERM, release_usb_device);
/*
* Parameter parsing, USB preparation/diagnosis, plausibility checks
*/

/* Check command arguments, use params instead of config file when given */
switch (readArguments(argc, argv)) {
case 0: /* no argument or -W, -q or -s */
break;
default: /* one or more arguments except -W, -q or -s */
if (!config_read) /* if arguments contain -c, the config file was already processed */
if (verbose) printf("Taking all parameters from the command line\n\n");
}

if (verbose)
printVersion();

if (verbose)
printConfig();

/* libusb initialization */
usb_init();

if (verbose)
usb_set_debug(15);

usb_find_busses();
usb_find_devices();

/* Plausibility checks. The default IDs are mandatory */
if (!(DefaultVendor && DefaultProduct)) {
SHOW_PROGRESS("No default vendor/product ID given. Aborting.\n\n");
exit(1);
}
if (strlen(MessageContent)) {
if (strlen(MessageContent) % 2 != 0) {
fprintf(stderr, "Error: MessageContent hex string has uneven length. Aborting.\n\n");
exit(1);
}
if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Aborting.\n\n", MessageContent);
exit(1);
}
}
SHOW_PROGRESS("\n");

if (show_progress)
if (CheckSuccess && !(TargetVendor || TargetProduct || strlen(TargetProductList)) && !TargetClass)
printf("Note: target parameter missing; success check limited\n");

/* Count existing target devices, remember for success check */
if (TargetVendor || TargetClass) {
SHOW_PROGRESS("Looking for target devices ...\n");
search_devices(&targetDeviceCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, SEARCH_TARGET);
if (targetDeviceCount) {
SHOW_PROGRESS(" Found devices in target mode or class (%d)\n", targetDeviceCount);
} else
SHOW_PROGRESS(" No devices in target mode or class found\n");
}

/* Count default devices, get the last one found */
SHOW_PROGRESS("Looking for default devices ...\n");
dev = search_devices(&numDefaults, DefaultVendor, DefaultProduct, "\0", TargetClass, SEARCH_DEFAULT);
if (numDefaults) {
SHOW_PROGRESS(" Found devices in default mode or class (%d)\n", numDefaults);
} else {
SHOW_PROGRESS(" No devices in default mode or class found. Nothing to do. Bye.\n\n");
exit(0);
}
if (dev != NULL) {
devnum = dev->devnum;
busnum = (int)strtol(dev->bus->dirname,NULL,10);
SHOW_PROGRESS("Accessing device %03d on bus %03d ...\n", devnum, busnum);
devh = usb_open(dev);
} else {
SHOW_PROGRESS(" No default device found. Is it connected? Bye.\n\n");
exit(0);
}

/* Get class of default device/interface */
defaultClass = dev->descriptor.bDeviceClass;
if (defaultClass == 0)
defaultClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass;
else
if (dev->config[0].interface[0].altsetting[0].bInterfaceClass == 8 && defaultClass != 8) {
/* Weird device with default class other than 0 and differing interface class */
SHOW_PROGRESS("Ambiguous Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
defaultClass = 8;
}

/* Check or get endpoints */
if (strlen(MessageContent) || InquireDevice) {
if (!MessageEndpoint)
MessageEndpoint = find_first_bulk_output_endpoint(dev);
if (!MessageEndpoint) {
fprintf(stderr,"Error: message endpoint not given or found. Aborting.\n\n");
exit(1);
}
if (!ResponseEndpoint)
ResponseEndpoint = find_first_bulk_input_endpoint(dev);
if (!ResponseEndpoint) {
fprintf(stderr,"Error: response endpoint not given or found. Aborting.\n\n");
exit(1);
}
SHOW_PROGRESS("Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint);
}

if (MessageEndpoint && ResponseEndpoint) {
SHOW_PROGRESS("Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint);
} else
if (InquireDevice && defaultClass == 0x08) {
SHOW_PROGRESS("Endpoints not found, skipping SCSI inquiry\n");
InquireDevice = 0;
}

if (InquireDevice && show_progress) {
if (defaultClass == 0x08) {
SHOW_PROGRESS("Inquiring device details; driver will be detached ...\n");
detachDriver();
if (deviceInquire() >= 0)
InquireDevice = 2;
} else
SHOW_PROGRESS("Not a storage device, skipping SCSI inquiry\n");
}

deviceDescription();
if (show_progress) {
printf("\nUSB description data (for identification)\n");
printf("-------------------------\n");
printf("Manufacturer: %s\n", imanufact);
printf(" Product: %s\n", iproduct);
printf(" Serial No.: %s\n", iserial);
printf("-------------------------\n");
}

/* Some scenarios are exclusive, so check for unwanted combinations */
specialMode = DetachStorageOnly + HuaweiMode + SierraMode + SonyMode;
if ( specialMode > 1 ) {
SHOW_PROGRESS("Invalid mode combination. Check your configuration. Aborting.\n\n");
exit(1);
}

if ( !specialMode && !strlen(MessageContent) && AltSetting == -1 && Configuration == -1 )
SHOW_PROGRESS("Warning: no switching method given.\n");

/*
* The switching actions
*/

if (sysmode) {
openlog("usb_modeswitch", 0, LOG_SYSLOG);
syslog(LOG_NOTICE, "switching %04x:%04x (%s: %s)", DefaultVendor, DefaultProduct, imanufact, iproduct);
}

if (DetachStorageOnly) {
SHOW_PROGRESS("Only detaching storage driver for switching ...\n");
if (InquireDevice == 2) {
SHOW_PROGRESS(" Any driver was already detached for inquiry\n");
} else {
ret = detachDriver();
if (ret == 2)
SHOW_PROGRESS(" You may want to remove the storage driver manually\n");
}
}

if (HuaweiMode) {
switchHuaweiMode();
}
if (SierraMode) {
switchSierraMode();
}
if (GCTMode) {
detachDriver();
switchGCTMode();
}
if (SonyMode) {
if (CheckSuccess)
SHOW_PROGRESS("Note: ignoring CheckSuccess. Separate checks for Sony mode\n");
CheckSuccess = 0; /* separate and implied success control */
sonySuccess = switchSonyMode();
}

if (strlen(MessageContent) && MessageEndpoint) {
if (specialMode == 0) {
if (InquireDevice != 2)
detachDriver();
switchSendMessage();
} else
SHOW_PROGRESS("Warning: ignoring MessageContent. Can't combine with special mode\n");
}

if (Configuration != -1) {
switchConfiguration ();
}

if (AltSetting != -1) {
switchAltSetting();
}

if (ResetUSB) {
resetUSB();
}

if (CheckSuccess) {
if (checkSuccess()) {
if (sysmode) {
if (NoDriverLoading)
printf("ok:\n");
else
printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
}
} else
if (sysmode)
printf("fail:\n");
} else {
if (SonyMode)
if (sonySuccess) {
if (sysmode) {
syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
printf("ok:\n"); /* ACM device, no driver action */
}
SHOW_PROGRESS("-> device should be stable now. Bye.\n\n");
} else {
if (sysmode)
printf("fail:\n");
SHOW_PROGRESS("-> switching was probably not completed. Bye.\n\n");
}
else
SHOW_PROGRESS("-> Run lsusb to note any changes. Bye.\n\n");
}

if (sysmode)
closelog();
if (devh)
usb_close(devh);
exit(0);
}


/* Get descriptor strings if available (identification details) */
void deviceDescription ()
{
int ret;
char* c;
memset (imanufact, ' ', DESCR_MAX);
memset (iproduct, ' ', DESCR_MAX);
memset (iserial, ' ', DESCR_MAX);

if (dev->descriptor.iManufacturer) {
ret = usb_get_string_simple(devh, dev->descriptor.iManufacturer, imanufact, DESCR_MAX);
if (ret < 0)
fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
} else
strcpy(imanufact, "not provided");
c = strstr(imanufact, " ");
if (c)
memset((void*)c, '\0', 1);

if (dev->descriptor.iProduct) {
ret = usb_get_string_simple(devh, dev->descriptor.iProduct, iproduct, DESCR_MAX);
if (ret < 0)
fprintf(stderr, "Error: could not get description string \"product\"\n");
} else
strcpy(iproduct, "not provided");
c = strstr(iproduct, " ");
if (c)
memset((void*)c, '\0', 1);

if (dev->descriptor.iSerialNumber) {
ret = usb_get_string_simple(devh, dev->descriptor.iSerialNumber, iserial, DESCR_MAX);
if (ret < 0)
fprintf(stderr, "Error: could not get description string \"serial number\"\n");
} else
strcpy(iserial, "not provided");
c = strstr(iserial, " ");
if (c)
memset((void*)c, '\0', 1);

}

/* Print result of SCSI command INQUIRY (identification details) */
int deviceInquire ()
{
const unsigned char inquire_msg[] = {
0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
char *command;
char data[36];
int i, ret;

command = malloc(31);
if (command == NULL) {
ret = 1;
goto out;
}

memcpy(command, inquire_msg, sizeof (inquire_msg));

ret = usb_claim_interface(devh, Interface);
if (ret != 0) {
SHOW_PROGRESS(" Could not claim interface (error %d). Skipping device inquiry\n", ret);
goto out;
}
usb_clear_halt(devh, MessageEndpoint);

ret = usb_bulk_write(devh, MessageEndpoint, (char *)command, 31, 0);
if (ret < 0) {
SHOW_PROGRESS(" Could not send INQUIRY message (error %d)\n", ret);
goto out;
}

ret = usb_bulk_read(devh, ResponseEndpoint, data, 36, 0);
if (ret < 0) {
SHOW_PROGRESS(" Could not get INQUIRY response (error %d)\n", ret);
goto out;
}

i = usb_bulk_read(devh, ResponseEndpoint, command, 13, 0);

printf("\nSCSI inquiry data (for identification)\n");
printf("-------------------------\n");

printf(" Vendor String: ");
for (i = 8; i < 16; i++) printf("%c",data[i]);
printf("\n");

printf(" Model String: ");
for (i = 16; i < 32; i++) printf("%c",data[i]);
printf("\n");

printf("Revision String: ");
for (i = 32; i < 36; i++) printf("%c",data[i]);

printf("\n-------------------------\n");

out:
if (strlen(MessageContent) == 0)
usb_clear_halt(devh, MessageEndpoint);
usb_release_interface(devh, Interface);
free(command);
return ret;
}


void resetUSB ()
{
int success;
int bpoint = 0;

if (show_progress) {
printf("Resetting usb device ");
fflush(stdout);
}

sleep( 1 );
do {
success = usb_reset(devh);
if ( ((bpoint % 10) == 0) && show_progress ) {
printf(".");
fflush(stdout);
}
bpoint++;
if (bpoint > 100)
success = 1;
} while (success < 0);

if ( success ) {
SHOW_PROGRESS("\n Reset failed. Can be ignored if device switched OK.\n");
} else
SHOW_PROGRESS("\n OK, device was reset\n");
}


int switchSendMessage ()
{
int ret;

/* May be activated in future versions */
// if (MessageContent2[0] != '\0' || MessageContent3[0] != '\0')
// NeedResponse = 1;

SHOW_PROGRESS("Setting up communication with interface %d ...\n", Interface);
if (InquireDevice != 2) {
ret = usb_claim_interface(devh, Interface);
if (ret != 0) {
SHOW_PROGRESS(" Could not claim interface (error %d). Skipping message sending\n", ret);
return 0;
}
}
usb_clear_halt(devh, MessageEndpoint);
SHOW_PROGRESS("Using endpoint 0x%02x for message sending ...\n", MessageEndpoint);
if (show_progress)
fflush(stdout);

if ( sendMessage(MessageContent, 1) )
goto skip;

if (NeedResponse) {
SHOW_PROGRESS("Reading the response to the message (CSW) ...\n");
ret = read_bulk(ResponseEndpoint, ByteString, 0x200);
if (ret < 0)
goto skip;
}

if (strlen(MessageContent2)) {
if (MessageDelay) {
usb_release_interface(devh, Interface);
SHOW_PROGRESS("Delaying next message transfer for %d ms\n", MessageDelay);
usleep(MessageDelay*1000);
ret = usb_claim_interface(devh, Interface);
if (ret != 0) {
SHOW_PROGRESS(" Could not reclaim interface\n");
goto skip;
}
}
if ( sendMessage(MessageContent2, 2) )
goto skip;

if (NeedResponse) {
SHOW_PROGRESS("Reading the response to message 2 ...\n");
ret = read_bulk(ResponseEndpoint, ByteString, 0x200);
if (ret < 0)
goto skip;
}
}

if (strlen(MessageContent3)) {
if (MessageDelay) {
usb_release_interface(devh, Interface);
SHOW_PROGRESS("Delaying next message transfer for %d ms\n", MessageDelay);
usleep(MessageDelay*1000);
ret = usb_claim_interface(devh, Interface);
if (ret != 0) {
SHOW_PROGRESS(" Could not reclaim interface\n");
goto skip;
}
}
if ( sendMessage(MessageContent3, 3) )
goto skip;
if (NeedResponse) {
SHOW_PROGRESS("Reading the response to message 3 ...\n");
ret = read_bulk(ResponseEndpoint, ByteString, 0x200);
if (ret < 0)
goto skip;
}
}

SHOW_PROGRESS("Resetting response endpoint 0x%02x\n", ResponseEndpoint);
ret = usb_clear_halt(devh, ResponseEndpoint);
if (ret)
SHOW_PROGRESS(" Error resetting endpoint: %d\n", ret);
SHOW_PROGRESS("Resetting message endpoint 0x%02x\n", MessageEndpoint);
ret = usb_clear_halt(devh, MessageEndpoint);
if (ret)
SHOW_PROGRESS(" Error resetting endpoint: %d\n", ret);
ret = usb_release_interface(devh, Interface);
if (ret)
goto skip;
return 1;

skip:
SHOW_PROGRESS(" Device is gone, skipping any further commands\n");
usb_close(devh);
devh = 0;
return 2;
}


int switchConfiguration ()
{
int ret;

SHOW_PROGRESS("Changing configuration to %i ...\n", Configuration);
ret = usb_set_configuration(devh, Configuration);
if (ret == 0 ) {
SHOW_PROGRESS(" OK, configuration set\n");
return 1;
}
SHOW_PROGRESS(" Setting the configuration returned error %d. Trying to continue\n", ret);
return 0;
}


int switchAltSetting ()
{
int ret;

SHOW_PROGRESS("Changing to alt setting %i ...\n", AltSetting);
ret = usb_claim_interface(devh, Interface);
ret = usb_set_altinterface(devh, AltSetting);
usb_release_interface(devh, Interface);
if (ret != 0) {
SHOW_PROGRESS(" Changing to alt setting returned error %d. Trying to continue\n", ret);
return 0;
} else {
SHOW_PROGRESS(" OK, changed to alt setting\n");
return 1;
}
}


void switchHuaweiMode ()
{
int ret;

SHOW_PROGRESS("Sending Huawei control message ...\n");
ret = usb_control_msg(devh, USB_TYPE_STANDARD + USB_RECIP_DEVICE, USB_REQ_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
if (ret != 0) {
fprintf(stderr, "Error: sending Huawei control message failed (error %d). Aborting.\n\n", ret);
exit(1);
} else
SHOW_PROGRESS(" OK, Huawei control message sent\n");
}


void switchSierraMode ()
{
int ret;

SHOW_PROGRESS("Trying to send Sierra control message\n");
ret = usb_control_msg(devh, 0x40, 0x0b, 00000001, 0, buffer, 0, 1000);
if (ret != 0) {
fprintf(stderr, "Error: sending Sierra control message failed (error %d). Aborting.\n\n", ret);
exit(1);
} else
SHOW_PROGRESS(" OK, Sierra control message sent\n");
}


void switchGCTMode ()
{
int ret;

ret = usb_claim_interface(devh, Interface);
if (ret != 0) {
SHOW_PROGRESS(" Could not claim interface (error %d). Skipping GCT sequence \n", ret);
return;
}

SHOW_PROGRESS("Sending GCT control message 1 ...\n");
ret = usb_control_msg(devh, 0xa1, 0xa0, 0, Interface, buffer, 1, 1000);
SHOW_PROGRESS("Sending GCT control message 2 ...\n");
ret = usb_control_msg(devh, 0xa1, 0xfe, 0, Interface, buffer, 1, 1000);
SHOW_PROGRESS(" OK, GCT control messages sent\n");
usb_release_interface(devh, Interface);
}


int switchSonyMode ()
{
int i, found, ret;
detachDriver();

if (CheckSuccess) {
printf("Note: CheckSuccess pointless with Sony mode, disabling\n");
CheckSuccess = 0;
}

SHOW_PROGRESS("Trying to send Sony control message\n");
ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
if (ret < 0) {
fprintf(stderr, "Error: sending Sony control message failed (error %d). Aborting.\n\n", ret);
exit(1);
} else
SHOW_PROGRESS(" OK, control message sent, waiting for device to return ...\n");

usb_close(devh);
devh = 0;

/* Now waiting for the device to reappear */
devnum=-1;
busnum=-1;
i=0;
dev = 0;
while ( dev == 0 && i < 30 ) {
if ( i > 5 ) {
usb_find_busses();
usb_find_devices();
dev = search_devices(&found, DefaultVendor, DefaultProduct, "\0", TargetClass, SEARCH_TARGET);
}
if ( dev != 0 )
break;
sleep(1);
if (show_progress) {
printf("#");
fflush(stdout);
}
i++;
}
SHOW_PROGRESS("\n After %d seconds:",i);
if ( dev ) {
SHOW_PROGRESS(" device came back, proceeding\n");
devh = usb_open( dev );
if (devh == 0) {
fprintf(stderr, "Error: could not get handle on device\n");
return 0;
}
} else {
SHOW_PROGRESS(" device still gone, cancelling\n");
return 0;
}

sleep(1);

SHOW_PROGRESS("Sending Sony control message again ...\n");
ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
if (ret < 0) {
fprintf(stderr, "Error: sending Sony control message (2) failed (error %d)\n", ret);
return 0;
}
SHOW_PROGRESS(" OK, control message sent\n");
return 1;
}


/* Detach driver either as the main action or as preparation for other
* switching methods
*/
int detachDriver()
{
int ret;

#ifndef LIBUSB_HAS_GET_DRIVER_NP
printf(" Cant't do driver detection and detaching on this platform.\n");
return 2;
#endif

SHOW_PROGRESS("Looking for active driver ...\n");
ret = usb_get_driver_np(devh, Interface, buffer, BUF_SIZE);
if (ret != 0) {
SHOW_PROGRESS(" No driver found. Either detached before or never attached\n");
return 1;
}
SHOW_PROGRESS(" OK, driver found (\"%s\")\n", buffer);
if (DetachStorageOnly && strcmp(buffer,"usb-storage")) {
SHOW_PROGRESS(" Warning: driver is not usb-storage\n");
}

#ifndef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
SHOW_PROGRESS(" Can't do driver detaching on this platform\n");
return 2;
#endif


ret = usb_detach_kernel_driver_np(devh, Interface);
if (ret == 0) {
SHOW_PROGRESS(" OK, driver \"%s\" detached\n", buffer);
} else
SHOW_PROGRESS(" Driver \"%s\" detach failed with error %d. Trying to continue\n", buffer, ret);
return 1;
}


int sendMessage(char* message, int count)
{
int message_length, ret;

if (strlen(message) % 2 != 0) {
fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
return 1;
}
message_length = strlen(message) / 2;
if ( hexstr2bin(message, ByteString, message_length) == -1) {
fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n", count, MessageContent);
return 1;
}
SHOW_PROGRESS("Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
fflush(stdout);
ret = write_bulk(MessageEndpoint, ByteString, message_length);
if (ret == -19)
return 1;

return 0;
}


int checkSuccess()
{
int i=0, ret;
int newTargetCount, success=0;

SHOW_PROGRESS("\nChecking for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
sleep(1);

/* if target ID is not given but target class is, assign default as target;
* it will be needed for sysmode output
*/
if (!TargetVendor && TargetClass) {
TargetVendor = DefaultVendor;
TargetProduct = DefaultProduct;
}

if (devh) // devh is 0 if device vanished during command transmission
for (i=0; i < CheckSuccess; i++) {

/* Test if default device still can be accessed; positive result does
* not necessarily mean failure
*/
SHOW_PROGRESS(" Waiting for original device to vanish ...\n");

ret = usb_claim_interface(devh, Interface);
if (ret < 0) {
SHOW_PROGRESS(" Original device can't be accessed anymore. Good.\n");
if (i == CheckSuccess-1)
SHOW_PROGRESS(" If you want target checking, increase 'CheckSuccess' value.\n");
usb_close(devh);
devh = 0;
break;
} else
usb_release_interface(devh, Interface);

if (i == CheckSuccess-1) {
SHOW_PROGRESS(" Original device still present after the timeout\n\nMode switch most likely failed. Bye.\n\n");
} else
sleep(1);
}
else
SHOW_PROGRESS(" Original device is gone already, not checking\n");


if ( TargetVendor && (TargetProduct || strlen(TargetProductList)) )

/* Recount target devices (compare with previous count) if target data is given.
* Target device on the same bus with higher device number is returned,
* description is read for syslog message
*/
for (i=i; i < CheckSuccess; i++) {
SHOW_PROGRESS(" Searching for target devices ...\n");
usb_find_devices();
dev = search_devices(&newTargetCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, SEARCH_TARGET);
if (dev && (newTargetCount > targetDeviceCount)) {
devh = usb_open(dev);
deviceDescription();
usb_close(devh);
devh = 0;
if (verbose) {
printf("\nFound target device %03d on bus %03d\n", \
dev->devnum, (int)strtol(dev->bus->dirname,NULL,10));
printf("\nTarget device description data\n");
printf("-------------------------\n");
printf("Manufacturer: %s\n", imanufact);
printf(" Product: %s\n", iproduct);
printf(" Serial No.: %s\n", iserial);
printf("-------------------------\n");
}
SHOW_PROGRESS(" Found correct target device\n\nMode switch succeeded. Bye.\n\n");
success = 2;
break;
}
if (i == CheckSuccess-1) {
SHOW_PROGRESS(" No new devices in target mode or class found\n\nMode switch has failed. Bye.\n\n");
} else
sleep(1);
}
else
/* No target data given, rely on the vanished device */
if (!devh) {
SHOW_PROGRESS(" (For a better success check provide target IDs or class)\n");
SHOW_PROGRESS(" Original device vanished after switching\n\nMode switch most likely succeeded. Bye.\n\n");
success = 1;
}

switch (success) {
case 2:
if (sysmode)
syslog(LOG_NOTICE, "switched to %04x:%04x (%s: %s)", TargetVendor, TargetProduct, imanufact, iproduct);
success = 1;
break;
case 1:
if (sysmode)
syslog(LOG_NOTICE, "device seems to have switched");
default:
;
}
if (sysmode)
closelog();

return success;

}


int write_bulk(int endpoint, char *message, int length)
{
int ret;
ret = usb_bulk_write(devh, endpoint, message, length, 100);
if (ret >= 0 ) {
SHOW_PROGRESS(" OK, message successfully sent\n");
} else
if (ret == -19) {
SHOW_PROGRESS(" Device seems to have vanished right after sending. Good.\n");
} else
SHOW_PROGRESS(" Sending the message returned error %d. Trying to continue\n", ret);
return ret;

}

int read_bulk(int endpoint, char *buffer, int length)
{
int ret;
ret = usb_bulk_read(devh, endpoint, buffer, length, 100);
usb_bulk_read(devh, endpoint, buffer, 13, 100);
if (ret >= 0 ) {
SHOW_PROGRESS(" OK, response successfully read (%d bytes).\n", ret);
} else
if (ret == -19) {
SHOW_PROGRESS(" Device seems to have vanished after reading. Good.\n");
} else
SHOW_PROGRESS(" Response reading got error %d, can probably be ignored\n", ret);
return ret;

}

void release_usb_device(int dummy) {
SHOW_PROGRESS("Program cancelled by system. Bye.\n\n");
if (devh) {
usb_release_interface(devh, Interface);
usb_close(devh);
}
if (sysmode)
closelog();
exit(0);

}


/* Iterates over busses and devices, counts the ones with the given
* ID/class and returns the last one of them
*/
struct usb_device* search_devices( int *numFound, int vendor, int product, char* productList, int targetClass, int mode)
{
struct usb_bus *bus;
char *listcopy, *token, buffer[2];
int devClass;
struct usb_device* right_dev = NULL;

/* only target class given, target vendor and product assumed unchanged */
if ( targetClass && !(vendor || product) ) {
vendor = DefaultVendor;
product = DefaultProduct;
}
*numFound = 0;

/* Sanity check */
if (!vendor || (!product && productList == '\0') )
return NULL;

if (productList != '\0')
listcopy = malloc(strlen(productList)+1);

for (bus = usb_get_busses(); bus; bus = bus->next) {
struct usb_device *dev;
for (dev = bus->devices; dev; dev = dev->next) {
if (verbose)
printf (" searching devices, found USB ID %04x:%04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
if (dev->descriptor.idVendor != vendor)
continue;
if (verbose)
printf (" found matching vendor ID\n");
// product list given
if ( strlen(productList) ) {
strcpy(listcopy, productList);
token = strtok(listcopy, ",");
while (token != NULL) {
if (strlen(token) != 4) {
SHOW_PROGRESS("Error: entry in product ID list has wrong length: %s. Ignoring\n", token);
goto NextToken;
}
if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
SHOW_PROGRESS("Error: entry in product ID list is not a hex string: %s. Ignoring\n", token);
goto NextToken;
}
product = 0;
product += (unsigned char)buffer[0];
product <<= 8;
product += (unsigned char)buffer[1];
if (product == dev->descriptor.idProduct) {
if (verbose)
printf (" found matching product ID from list\n");
(*numFound)++;
if (busnum == -1)
right_dev = dev;
else
if (dev->devnum >= devnum && (int)strtol(dev->bus->dirname,NULL,10) == busnum) {
right_dev = dev;
TargetProduct = dev->descriptor.idProduct;
break;
}
}

NextToken:
token = strtok(NULL, ",");
}
/* Product ID is given */
} else
if (product == dev->descriptor.idProduct) {
if (verbose)
printf (" found matching product ID\n");
if (targetClass == 0) {
(*numFound)++;
right_dev = dev;
if (verbose)
printf (" adding device\n");
} else {
devClass = dev->descriptor.bDeviceClass;
if (devClass == 0)
devClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass;
else
/* Check for some quirky devices */
if (devClass != dev->config[0].interface[0].altsetting[0].bInterfaceClass)
devClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass;
if (devClass == targetClass) {
if (verbose)
printf (" target class %02x matching\n", targetClass);
if (mode == SEARCH_TARGET) {
(*numFound)++;
right_dev = dev;
if (verbose)
printf (" adding device\n");
} else
if (verbose)
printf (" not adding device as default\n");
} else {
if (verbose)
printf (" target class %02x not matching\n", targetClass);
if (mode == SEARCH_DEFAULT) {
(*numFound)++;
right_dev = dev;
if (verbose)
printf (" adding device as default\n");
}
}
}
/* hack: if busnum has other than init value, we are called from
* successCheck() and do probe for plausible new devnum/busnum
*/
if (busnum != -1)
if (dev->devnum < devnum || (int)strtol(dev->bus->dirname,NULL,10) != busnum) {
if (verbose)
printf (" busnum/devnum indicates an unrelated device\n");
right_dev = NULL;
}
}
}
}
if (productList != NULL)
free(listcopy);
return right_dev;
}


#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80

/* Autodetect bulk endpoints (ab) */

int find_first_bulk_output_endpoint(struct usb_device *dev)
{
int i;
struct usb_interface_descriptor *alt = &(dev->config[0].interface[0].altsetting[0]);
struct usb_endpoint_descriptor *ep;

for(i=0;i < alt->bNumEndpoints;i++) {
ep=&(alt->endpoint[i]);
if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT ) ) {
return ep->bEndpointAddress;
}
}

return 0;
}


int find_first_bulk_input_endpoint(struct usb_device *dev)
{
int i;
struct usb_interface_descriptor *alt = &(dev->config[0].interface[0].altsetting[0]);
struct usb_endpoint_descriptor *ep;

for(i=0;i < alt->bNumEndpoints;i++) {
ep=&(alt->endpoint[i]);
if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) ) {
return ep->bEndpointAddress;
}
}

return 0;
}



/* Parameter parsing */

char* ReadParseParam(const char* FileName, char *VariableName)
{
static char Str[LINE_DIM];
char *VarName, *Comment=NULL, *Equal=NULL;
char *FirstQuote, *LastQuote, *P1, *P2;
int Line=0, Len=0, Pos=0;
FILE *file=fopen(FileName, "r");

if (file==NULL) {
fprintf(stderr, "Error: Could not find file %s\n\n", FileName);
exit(1);
}

while (fgets(Str, LINE_DIM-1, file) != NULL) {
Line++;
Len=strlen(Str);
if (Len==0) goto Next;
if (Str[Len-1]=='\n' or Str[Len-1]=='\r') Str[--Len]='\0';
Equal = strchr (Str, '='); // search for equal sign
Pos = strcspn (Str, ";#!"); // search for comment
Comment = (Pos==Len) ? NULL : Str+Pos;
if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) goto Next; // Only comment
*Equal++ = '\0';
if (Comment!=NULL) *Comment='\0';

// String
FirstQuote=strchr (Equal, '"'); // search for double quote char
LastQuote=strrchr (Equal, '"');
if (FirstQuote!=NULL) {
if (LastQuote==NULL) {
fprintf(stderr, "Error reading parameter file %s line %d - Missing end quote.\n", FileName, Line);
goto Next;
}
*FirstQuote=*LastQuote='\0';
Equal=FirstQuote+1;
}

// removes leading/trailing spaces
Pos=strspn (Str, " \t");
if (Pos==strlen(Str)) {
fprintf(stderr, "Error reading parameter file %s line %d - Missing variable name.\n", FileName, Line);
goto Next; // No function name
}
while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
if (P1!=NULL) *P1='\0';
else if (P2!=NULL) *P2='\0';
VarName=Str+Pos;

Pos=strspn (Equal, " \t");
if (Pos==strlen(Equal)) {
fprintf(stderr, "Error reading parameter file %s line %d - Missing value.\n", FileName, Line);
goto Next; // No function name
}
Equal+=Pos;

if (strcmp(VarName, VariableName)==0) { // Found it
fclose(file);
return Equal;
}
Next:;
}

fclose(file);
return NULL;
}


int hex2num(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}


int hex2byte(const char *hex)
{
int a, b;
a = hex2num(*hex++);
if (a < 0)
return -1;
b = hex2num(*hex++);
if (b < 0)
return -1;
return (a << 4) | b;
}

int hexstr2bin(const char *hex, char *buffer, int len)
{
int i;
int a;
const char *ipos = hex;
char *opos = buffer;

for (i = 0; i < len; i++) {
a = hex2byte(ipos);
if (a < 0)
return -1;
*opos++ = a;
ipos += 2;
}
return 0;
}

void printVersion()
{
char* version = VERSION;
printf(" * usb_modeswitch: handle USB devices with multiple modes\n");
printf(" * Version %s (C) Josua Dietze 2010\n", version);
printf(" * Based on libusb0 (0.1.12 and above)\n\n");
printf(" ! PLEASE REPORT NEW CONFIGURATIONS !\n\n");
}

void printHelp()
{
printf ("Usage: usb_modeswitch [-hvpVPmMrdHn] [-c filename]\n\n");
printf (" -h, --help this help\n");
printf (" -e, --version print version information and exit\n");
printf (" -v, --default-vendor NUM vendor ID of original mode (mandatory)\n");
printf (" -p, --default-product NUM product ID of original mode (mandatory)\n");
printf (" -V, --target-vendor NUM target mode vendor ID (optional)\n");
printf (" -P, --target-product NUM target mode product ID (optional)\n");
printf (" -C, --target-class NUM target mode device class (optional)\n");
printf (" -m, --message-endpoint NUM direct the message transfer there (optional)\n");
printf (" -M, --message-content <msg> message to send (hex number as string)\n");
printf (" -2 <msg>, -3 <msg> additional messages to send (-n recommended)\n");
printf (" -n, --need-response read response to the message transfer (CSW)\n");
printf (" -r, --response-endpoint NUM read response from there (optional)\n");
printf (" -d, --detach-only detach the active driver, no further action\n");
printf (" -H, --huawei-mode apply a special procedure\n");
printf (" -S, --sierra-mode apply a special procedure\n");
printf (" -O, --sony-mode apply a special procedure\n");
printf (" -G, --gct-mode apply a special procedure\n");
printf (" -R, --reset-usb reset the device after all other actions\n");
printf (" -Q, --quiet don't show progress or error messages\n");
printf (" -W, --verbose print all settings and debug output\n");
printf (" -D, --sysmode specific result and syslog message\n");
printf (" -s, --success NUM check switching result after NUM secs\n");
printf (" -I, --no-inquire do not get SCSI attributes (default on)\n\n");
printf (" -c, --config-file <filename> load configuration from file\n\n");
printf (" -i, --interface NUM select initial USB interface (default 0)\n");
printf (" -u, --configuration NUM select USB configuration\n");
printf (" -a, --altsetting NUM select alternative USB interface setting\n\n");
}
! end of PROC printHelp
==============================
Ian Collins
2010-09-17 23:53:05 UTC
Permalink
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
How much are you paying?

<1400 odd lines snipped>
--
Ian Collins
n***@gmail.com
2010-09-18 10:04:59 UTC
Permalink
Post by Ian Collins
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
How much are you paying?
If you've got nothing to contribute to the colaborators' forum,
then take your begging bowl and go out on the street.
The original coder made GPL contribution.
And I hope to have added some value.
Here's some more:-
Q. why has *nix got `p2c` but no `c2p` ?
A. apparently because PASCAL is designed & minimalist whereas C
is an evolved mess; and you can map from P to a reduced C, but
not [so easily] from all the multiple possibilities of a C construct
to the canonical P equivalent ?

But since syntax-coulour editors for C exist, that's half the job.
Mnay worthwhile tasks can be achieved by heuristic methods:
ie. with some human input, combined with the computer's
contribution.
luserXtrog
2010-09-18 10:24:16 UTC
Permalink
Post by n***@gmail.com
Post by Ian Collins
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
How much are you paying?
If you've got nothing to contribute to the colaborators' forum,
then take your begging bowl and go out on the street.
The original coder made GPL contribution.
And I hope to have added some value.
Here's some more:-
Q. why has *nix got `p2c` but no `c2p` ?
A. apparently because PASCAL is designed & minimalist whereas C
is an evolved mess; and you can map from P to a reduced C, but
not [so easily] from all the multiple possibilities of a C construct
to the canonical P equivalent ?
But since syntax-coulour editors for C exist, that's half the job.
ie. with some human input, combined with the computer's
contribution.
A search for "why pascal is not my favorite programming language"
might elucidate some of the differences and why c2p in general
isn't really possible. It might be possible for any given specific
case; but there are things in c that weren't dreamt of in pascal's
philosophy. I think function pointer is one.

--
boogaboogaboo
Ian Collins
2010-09-18 10:30:26 UTC
Permalink
Post by n***@gmail.com
Post by Ian Collins
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
How much are you paying?
If you've got nothing to contribute to the colaborators' forum,
then take your begging bowl and go out on the street.
Which collaborators forum would that be? This is Usenet.
Post by n***@gmail.com
The original coder made GPL contribution.
And I hope to have added some value.
Here's some more:-
Q. why has *nix got `p2c` but no `c2p` ?
C has constructs Pascal lacks.
--
Ian Collins
Marco van de Voort
2010-09-18 18:55:30 UTC
Permalink
Post by Ian Collins
Post by n***@gmail.com
The original coder made GPL contribution.
And I hope to have added some value.
Here's some more:-
Q. why has *nix got `p2c` but no `c2p` ?
C has constructs Pascal lacks.
And vice versa.
Seebs
2010-09-18 18:28:45 UTC
Permalink
Post by n***@gmail.com
If you've got nothing to contribute to the colaborators' forum,
then take your begging bowl and go out on the street.
This is not a forum for other people do do your work for you; it's for
*discussion*. If you want people to collaborate with you on code changes,
this is the wrong forum.
Post by n***@gmail.com
And I hope to have added some value.
No offense to our Pascal friends, but I really don't think that converting
this code to Pascal will add value. You haven't exactly given us any reason
for which you think you need to do this.
Post by n***@gmail.com
Here's some more:-
Q. why has *nix got `p2c` but no `c2p` ?
A. apparently because PASCAL is designed & minimalist whereas C
is an evolved mess; and you can map from P to a reduced C, but
not [so easily] from all the multiple possibilities of a C construct
to the canonical P equivalent ?
Exactly. There are huge numbers of C programs for which there is no
Pascal equivalent, at least at the level of "code which goes through the
same process". You could write a new program which took the same inputs
and the same outputs, but it would likely be unrecognizably different
for most non-trivial programs.
Post by n***@gmail.com
But since syntax-coulour editors for C exist, that's half the job.
No, no it isn't. It's not even one percent of the job.
Post by n***@gmail.com
ie. with some human input, combined with the computer's
contribution.
But not translating stuff from one language to another where one of the
languages has capabilities that the other intentionally omits.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-***@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.
Marco van de Voort
2010-09-18 18:54:45 UTC
Permalink
Post by n***@gmail.com
Q. why has *nix got `p2c` but no `c2p` ?
A. apparently because PASCAL is designed & minimalist whereas C
is an evolved mess; and you can map from P to a reduced C, but
not [so easily] from all the multiple possibilities of a C construct
to the canonical P equivalent ?
Actually you can, but the trouble is the result is useless, since before
C2P, first the preprocessor must be run to produce actual C code.

Then the preprocessed C code can be fairly easily get mapped to Pascal.

But that result is useless for what most people want to do with the resulting
C code, and it only works for complete programs, not headers.

So the main problem is due to the heavy preprocessor use of C, which allows
to define stuff incompletely.

In theory, a #define in header can be used in two totally different context,
giving the earlier #define two possible sane translations (without
preprocessor)
Nick Keighley
2010-09-18 09:13:55 UTC
Permalink
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
I see no attempt to translate the code into Pascal

I don't think there's any way to avoid learning C. This is a fairly
tangled and platform specific bit of C and to express it in Pascal
you're going to have to understand what it does. And to understand
what it does you're going to have to learn C.
Post by n***@gmail.com
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
I'll clean-up and integrate all contributions.
<snip>
Post by n***@gmail.com
/*
  Mode switching tool for controlling flip flop (multiple device) USB gear
  Version 1.1.4, 2010/08/17
  Copyright (C) 2007, 2008, 2009, 2010 Josua Dietze
 http://www.gnu.org/licenses/gpl.txt*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <ctype.h>
#include <getopt.h>
#include <syslog.h>
#include <usb.h>
#include "usb_modeswitch.h"
I suspect you need to look inside these headers for some of the types
etc.

<snip>
Post by n***@gmail.com
struct usb_dev_handle *devh;
! is '*dev' a pointer to a RECORD called usb_device ?? <------
devh is a pointer to a struct usb_dev_handle. A struct is analogous to
a Pascal record.

<snip>
Post by n***@gmail.com
/* Settable Interface and Configuration (for debugging mostly) (jmw) */
int Interface = 0, Configuration = -1, AltSetting = -1;
static struct option long_options[] = {
        {"help",                              no_argument, 0, 'h'},
        {"version",                           no_argument, 0, 'e'},
<snip>
Post by n***@gmail.com
        {0, 0, 0, 0}};
! is this a RECORD containing an ARRAY OF <strings>?
it's an array of structs. Each struct seems to have a string (char*)
member, maybe two into and a char. If you want to know more about the
struct find the definition.
Post by n***@gmail.com
void readConfigFile(const char *configFilename)
{
        if (verbose) printf("Reading config file: %s\n", configFilename);
        ParseParamHex(configFilename, TargetVendor);
        ParseParamHex(configFilename, TargetProduct);
<snip>
Post by n***@gmail.com
! all the above PROC calls, initialies their 2nd arg, which is a global-var.
!   readConfigFile(optarg)
! with ONE arg  -- which doesn't match its declaration: of 2 args ?  
sorry? where is it declared with two arguments?
Post by n***@gmail.com
        /* TargetProductList has priority over TargetProduct */
        if (strlen(TargetProductList))
        {
                TargetProduct = 0;
                SHOW_PROGRESS("Warning: TargetProductList overrides TargetProduct!\n");
        }
        config_read = 1;}
! end of PROC readConfigFile
boredom sets in

<snip>
n***@gmail.com
2010-09-19 23:54:16 UTC
Permalink
Post by Nick Keighley
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
I see no attempt to translate the code into Pascal
It's the algorithm that I want, and Pascal-like/P-code is best.
Post by Nick Keighley
Post by n***@gmail.com
struct usb_dev_handle *devh;
! is '*dev' a pointer to a RECORD called usb_device ?? <------
devh is a pointer to a struct usb_dev_handle.
A struct is analogous to a Pascal record.
You've paraphrased my sentence into two.
Post by Nick Keighley
Post by n***@gmail.com
static struct option long_options[] = {
{"help", =
no_argument, 0, 'h'},
Post by n***@gmail.com
{"version", =
no_argument, 0, 'e'},
<snip>
Post by n***@gmail.com
{0, 0, 0, 0}};
! is this a RECORD containing an ARRAY OF <strings>?
it's an array of structs.
OK, an array of RECORDS - we must use the destination
language's notation. Ie. RECORDS, not 'structures'.
Doesn't each RECORD contain:
a string: eg "version";
?! wherewould <no_argument> be defined ?
?! if <"version"> is a string, what's <'e'> ?
Post by Nick Keighley
Each struct seems to have a string (char*)
member, maybe two into and a char. If you want to know more
about the struct find the definition.
No, isn't it defined right here?
Post by Nick Keighley
Post by n***@gmail.com
! readConfigFile(optarg)
! with ONE arg -- which doesn't match its declaration: of 2 args ?
sorry? where is it declared with two arguments?
void readConfigFile(const char *configFilename)
OK, is this one arg:
<a pointer to a string> ?
What does the 'const' mean?
Post by Nick Keighley
boredom sets in
Well you've moved it along by adding value.

Thanks,

== Chris Glur
Nick Keighley
2010-09-20 09:03:11 UTC
Permalink
<snip>
Post by n***@gmail.com
Post by Nick Keighley
Post by n***@gmail.com
struct usb_dev_handle *devh;
! is '*dev' a pointer to a RECORD called usb_device ?? <------
devh is a pointer to a struct usb_dev_handle.
A struct is analogous to a Pascal record.
You've paraphrased my sentence into two.
and so? Actually I corrected your statement.
Post by n***@gmail.com
Post by Nick Keighley
Post by n***@gmail.com
static struct option long_options[] = {
        {"help",                         =
     no_argument, 0, 'h'},
Post by n***@gmail.com
        {"version",                       =
    no_argument, 0, 'e'},
<snip>
Post by n***@gmail.com
        {0, 0, 0, 0}};
! is this a RECORD containing an ARRAY OF <strings>?
it's an array of structs.
OK, an array of RECORDS - we must use the destination
you've buggered up the quoting. Please don't misquote me. It *isn't*
an array of records.

****
Post by n***@gmail.com
! is this a RECORD containing an ARRAY OF <strings>?
I replied:
***
it's an array of structs. Each struct seems to have a string (char*)
member, maybe two into and a char. If you want to know more about the
struct find the definition.
***
Post by n***@gmail.com
language's notation. Ie. RECORDS, not 'structures'.
  a string: eg "version";
  ?! wherewould <no_argument> be defined ?
no idea what you are talking about.If you want to omit the string you
could pass an empty string "" or a null pointer, NULL
Post by n***@gmail.com
  ?! if <"version"> is a string, what's <'e'> ?
'e' is a char literal.
That is typically it's a character (though it can also be regarded as
a small integer)
Post by n***@gmail.com
Post by Nick Keighley
Each struct seems to have a string (char*)
member, maybe two into and a char.
didn't you read this bit?
Post by n***@gmail.com
Post by Nick Keighley
If you want to know more
about the struct find the definition.
No, isn't it defined right here?
no. The struct isn't defined here. An array of structs is defined
here. This stuff shouldn't be difficult for a Pascal programmer.
Post by n***@gmail.com
Post by Nick Keighley
Post by n***@gmail.com
!   readConfigFile(optarg)
! with ONE arg  -- which doesn't match its declaration: of 2 args ?  
sorry? where is it declared with two arguments?
void readConfigFile(const char *configFilename)
yes...
Post by n***@gmail.com
 <a pointer to a string> ?
nope. A pointer to a char. Because of C's loosness about pointers and
arrays. An array of strings can be passed as an argment (which then
gets converted to a pointer to the first element of the array). A
string in C is a nul (that is, zero) terminated array of chars.
Effectivly the argument is a string.
Post by n***@gmail.com
 What does the 'const' mean?
constant. The body of the function cannot modify the thing pointed to.
This can enable optimisations and generally it's a good idea to give
the compiler as much information about your intents as possible.

<snip>
John Bode
2010-09-20 18:25:13 UTC
Permalink
Post by Nick Keighley
<snip>
[moar snip]
Post by Nick Keighley
****
Post by n***@gmail.com
! is this a RECORD containing an ARRAY OF <strings>?
***
it's an array of structs. Each struct seems to have a string (char*)
member, maybe two into and a char. If you want to know more about the
struct find the definition.
***
...which is more than likely in the usb_modeswitch.h file #included at
the beginning of the program.

The line

static struct option long_option[]

declares an array named "long_option" of type "struct option" with
storage class "static" (which among other things prevents the symbol
name from being exported to the linker, essentially making it
"private" to this source file, but not in the way most OO types would
think of "private") and initializes it with the values between the
brackets; the size is determined from the number of initializers.
Since each element of the array is of struct type, each initializer in
the list is also bracketed with { and }.
Post by Nick Keighley
Post by n***@gmail.com
language's notation. Ie. RECORDS, not 'structures'.
  a string: eg "version";
  ?! wherewould <no_argument> be defined ?
Again, probably in the usb_modeswitch.h file.
Nick Keighley
2010-09-21 07:52:41 UTC
Permalink
<snip>
Post by Nick Keighley
Post by n***@gmail.com
! is this a RECORD containing an ARRAY OF <strings>?
***
it's an array of structs. Each struct seems to have a string (char*)
member, maybe two [ints] and a char. If you want to know more about the
struct find the definition.
***
note correction

<snip>
Post by Nick Keighley
Post by n***@gmail.com
Post by Nick Keighley
Each struct seems to have a string (char*)
member, maybe two [ints] and a char.
didn't you read this bit?
note correction

<snip>
Post by Nick Keighley
Post by n***@gmail.com
 <a pointer to a string> ?
nope. A pointer to a char. Because of C's loosness about pointers and
arrays. An array of [chars] can be passed as an argment (which then
gets converted to a pointer to the first element of the array). A
string in C is a nul (that is, zero) terminated array of chars.
Effectivly the argument is a string.
Post by n***@gmail.com
 What does the 'const' mean?
note correction
BartC
2010-09-18 09:55:30 UTC
Permalink
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
I'll clean-up and integrate all contributions.
Copyright (C) 2007, 2008, 2009, 2010 Josua Dietze
http://www.gnu.org/licenses/gpl.txt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <ctype.h>
#include <getopt.h>
#include <syslog.h>
#include <usb.h>
#include "usb_modeswitch.h"
! various IMPORTs
Do you intend also to translate the code of these usb modules? Or do you
expect these C modules to link statically with the Pascal code? If that is
possible, you might need to define an interface to the C module, in the
Pascal code.

Sort out these possibilities first before worrying about translating the
rest of the code. If linking Pascal to C is feasible, then you may need not
need to translate at all... Just modify this module so that it can be linked
in the same way to a small Pascal program that just calls an entry point in
the C.
Post by n***@gmail.com
#define SEARCH_DEFAULT 0
#define SEARCH_TARGET 1
! various CONSTs <------
Yes, these are all the easy bits. The code here can be translated
mechanically. It's all the code that isn't here that is the problem.
--
Bartc
w***@yahoo.com
2010-09-18 20:29:44 UTC
Permalink
I've done a little bit of such conversion. Easy enough for simple C...
but it became increasingly difficult.

I finally reached a point that when I tried to convert a mildly
interesting C program to Pascal, that my nuts fell off...
Pascal J. Bourguignon
2010-09-19 11:14:29 UTC
Permalink
Post by w***@yahoo.com
I've done a little bit of such conversion. Easy enough for simple C...
but it became increasingly difficult.
I finally reached a point that when I tried to convert a mildly
interesting C program to Pascal, that my nuts fell off...
If you are doing a mechanical translation, where you want the exact C
program to be run (thru a Pascal compiler), then you will have to
emulate the C virtual machine. For example, to convert this:

char* f(int i){
static char data="Hello World"; // is a array of 12 bytes
if((0<i) || (sizeof(data)<i)){ // Notice <, not <=.
return(0);
}else{
return(data+i);
}
}

you have to simulate C pointers and C memory, you cannot just map them
to Pascal pointers, which have different properties, and abilities.


On the other hand, you could convert the program from a higher level
point of view, where you try to understand "what" is done by the
program (not "how" it's done), and re-implement it in the target
language.

When you go from a low level programming language (assembler, C) to a
higher level programming language, it's better to use this higher
level approach.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Chris Burrows
2010-09-19 12:57:16 UTC
Permalink
Post by Pascal J. Bourguignon
On the other hand, you could convert the program from a higher level
point of view, where you try to understand "what" is done by the
program (not "how" it's done), and re-implement it in the target
language.
When you go from a low level programming language (assembler, C) to a
higher level programming language, it's better to use this higher
level approach.
+1. To me that is the only sensible way of doing it. Otherwise it's like
trying to convert a scrambled egg into an omelette ;-)

Chris Burrows
CFB Software
Astrobe v3.2: ARM Oberon-07 Development System
http://www.astrobe.com
Lance Schwerdfager
2012-06-08 15:11:21 UTC
Permalink
I really like the analogy, "trying to convert a scrambled egg into an
omelette". That describes the rote method of translation from one
programming language to another to a "T".

Lance Schwerdfager

n***@gmail.com
2010-09-19 23:53:56 UTC
Permalink
In article <***@kuiper.lan.informatimago.com>, ***@informatimago.com (Pascal J. Bourguignon) wrote:

--snip --
Post by Pascal J. Bourguignon
you have to simulate C pointers and C memory, you cannot just map them
to Pascal pointers, which have different properties, and abilities.
On the other hand, you could convert the program from a higher level
point of view, where you try to understand "what" is done by the
program (not "how" it's done), and re-implement it in the target
language.
When you go from a low level programming language (assembler, C)
to a higher level programming language, it's better to use this higher
level approach.
Yes, that's what I meant by using 'heuristic means': you 'pilot' the
vehicle/computer. The vehicle merely multiplies your natural
transportation capabilities. Eg. syntax colouring editors makes the
structure jump-out at you.

For this specific task, I actually want the algorithm, which I suspect
is rather simple, like:
* get the device's ID & get the corresponding driver; if any;
* otherwise try something from the heuristics-list based on the ID;
* otherwise send an evolving sequence of bytes to the device, while
monitoring it till is reracts as required.

Finding out if the C-boys could 'extract' the algorithm from my
description, plus the actual C-code, was an extra aim; which I
succeeded in doing: they can't.

Obviously I chose Pascal/P-code to represent the algorithm,
because it's the canonnical notation.

== Chris Glur.

BTW how's bablefish keeping?
I guess natural-language translators are quite useful now?
Could I collaborate with peole in China/Japan yet?
I've noticed that lots of Russian is written in latin-text.
Which is another example of operating at a higher-level,
ie. not being constrained by the noation.
Seebs
2010-09-20 00:01:09 UTC
Permalink
Post by n***@gmail.com
Finding out if the C-boys could 'extract' the algorithm from my
description, plus the actual C-code, was an extra aim; which I
succeeded in doing: they can't.
Given the actual code, I suspect it would be possible.

"Can't" and "won't" aren't the same thing. You've come across as hostile,
dismissive, and having a sense of entitlement. There are many traits which
will induce me to spend substantial time helping someone do something.
None of those are in evidence, here.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-***@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.
Ian Collins
2010-09-20 00:03:00 UTC
Permalink
Post by n***@gmail.com
Finding out if the C-boys could 'extract' the algorithm from my
description, plus the actual C-code, was an extra aim; which I
succeeded in doing: they can't.
You didn't complete you last sentence, it should have read "the can't be
bothered."!

No one is going to plough through 1400 lines of someone else's code
unless they have good reason to.
--
Ian Collins
BartC
2010-09-20 00:11:15 UTC
Permalink
Post by n***@gmail.com
Post by Pascal J. Bourguignon
When you go from a low level programming language (assembler, C)
to a higher level programming language, it's better to use this higher
level approach.
Yes, that's what I meant by using 'heuristic means': you 'pilot' the
vehicle/computer. The vehicle merely multiplies your natural
transportation capabilities. Eg. syntax colouring editors makes the
structure jump-out at you.
For this specific task, I actually want the algorithm, which I suspect
* get the device's ID & get the corresponding driver; if any;
* otherwise try something from the heuristics-list based on the ID;
* otherwise send an evolving sequence of bytes to the device, while
monitoring it till is reracts as required.
Finding out if the C-boys could 'extract' the algorithm from my
description, plus the actual C-code, was an extra aim; which I
succeeded in doing: they can't.
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
However what you posted was 100% C, with a half-dozen comments added each
containing a Pascal keyword.

Calling the code an 'algorithm' is glorifying it a bit; the code is not too
demanding and looks more like a script. No-one knowing both languages would
have much of a problem translating, other than motivation... However it has
dependencies elsewhere which need to be sorted out too, assuming your aim
was to have working Pascal code which does the same job ....
Post by n***@gmail.com
Obviously I chose Pascal/P-code to represent the algorithm,
because it's the canonnical notation.
... although it no longer sounds as though this was the case. It appears
more like you wanted a pseudo-coded, flowcharted, or English summary of what
the code was doing. So the Pascal was irrelevant.
--
bartc
John Bode
2010-09-20 17:30:48 UTC
Permalink
On Sep 19, 6:53 pm, ***@gmail.com wrote:

[snip]
Post by n***@gmail.com
For this specific task, I actually want the algorithm, which I suspect
* get the device's ID & get the corresponding driver; if any;
* otherwise try something from the heuristics-list based on the ID;
* otherwise send an evolving sequence of bytes to the device, while
  monitoring it till is reracts as required.
Then why didn't you ask for that in the first place instead of saying
"convert this code to Pascal"?
Post by n***@gmail.com
Finding out if the C-boys could 'extract' the algorithm from my
description, plus the actual C-code, was an extra aim; which I
succeeded in doing: they can't.
The code, while not the best in the world, is reasonably
straightforward, and a lot of the operations are fairly clear from
context. Just reading the debugging statements tells you what each
function is trying to do.

I'm not going to slog through 1000+ lines of code just to tell you
what you should be able to figure out with a couple of hours' study.
John Bode
2010-09-20 16:46:42 UTC
Permalink
Post by n***@gmail.com
Below is my attempted translation of a C-source to Pascal/Oberon.
My added lines start with "!".
Please add your contributions. Pseudo-code is OK too.
I'll clean-up and integrate all contributions.
You're in for a world of pain, here. What is the driving need to
convert this code to Pascal or Oberon? Why is it not sufficient in
its current form?

Just blapping up 1400 lines of C code and saying "how would I convert
this to Pascal" isn't going to net much enthusiasm (*especially* when
your attempted translation consists of lines like "various imports"
and "various declarations"). You would probably get better (and more
comprehensive) help if you posted a few representative lines of code
you didn't understand and ask about them specifically.

For example, you ask
Post by n***@gmail.com
! all the above PROC calls, initialies their 2nd arg, which is a global-var.
! readConfigFile(optarg)
! with ONE arg -- which doesn't match its declaration: of 2 args ?
The declaration of readConfigFile is

void readConfigFile(const char *configFilename)

which means it takes a single argument of type `const char *` (pointer
to const char). The value of the argument is the address of the first
in a sequence of characters (terminated by a 0-valued character), and
the `const` qualifier means that the function may not modify any of
the characters in that sequence.

You might want to invest in a good C language reference and take some
time to study it if you're serious about this (not to mention figuring
out *exactly* what this code is supposed to do and how it does it).
Chris Burrows
2010-09-20 23:23:12 UTC
Permalink
Post by John Bode
You're in for a world of pain, here. What is the driving need to
convert this code to Pascal or Oberon? Why is it not sufficient in
its current form?
There is no C or Pascal compiler on the Oberon operating system the OP is
using. However, Pascal would presumably be OK as there are tools to convert
95% of Standard Pascal to Oberon.
Post by John Bode
You would probably get better (and more
comprehensive) help if you posted a few representative lines of code
you didn't understand and ask about them specifically.
Agreed.

Chris Burrows
CFB Software
http://www.cfbsoftware.com
Marco van de Voort
2010-09-21 07:42:52 UTC
Permalink
Post by Chris Burrows
Post by John Bode
You would probably get better (and more
comprehensive) help if you posted a few representative lines of code
you didn't understand and ask about them specifically.
Agreed.
Better first confirm that the code that implements usb.h and
usb-modeswitch.h are available on Oberon. Otherwise even a perfectly
translated header is useless.
Continue reading on narkive:
Loading...