C code setjmp declare functions? - c

I'm absolutely not a coder, but I'm trying to get a very old program to compile from fortran to C, so that I can play a game i've not played in 20+ years (originally created on HP3000 in the late 70s!) on my linux box.
Someone has written a make.sh file, using f2c (fortran to C) so that it can compile using GCC under linux, but that was done many moons ago.
I'm getting the following error message:
stubs.c: In function ‘exexc_’:
stubs.c:76:13: warning: implicit declaration of function ‘mmsa_’; did
you mean ‘memset’? [-Wimplicit-function-declaration]
case 'A': mmsa_(); break;
The relevant piece of code i.e. exexc function in stubs.c is:
#include <setjmp.h>
int setjmp(jmp_buf env);
void exexc_(name, i1, i2, i3, i4, i5, namelen)
char *name;
shortint *i1, *i2, *i3, *i4, *i5;
long namelen;
{
static jmp_buf env;
static int first = 1;
static char segment[6];
ipx[0] = *i1;
ipx[1] = *i2;
ipx[2] = *i3;
ipx[3] = *i4;
ipx[4] = *i5;
strncpy(segment, name, namelen);
if( ! first ) longjmp(env, 1);
if( first )
{
first = 0;
setjmp(env);
switch(segment[3]) {
case 'A': mmsa_(); break;
case 'B': mmsb_(); break;
case 'C': mmsc_(); break;
case 'D': mmsd_(); break;
case 'E': mmse_(); break;
case 'F': mmsf_(); break;
case 'G': mmsg_(); break;
case 'H': mmsh_(); break;
case 'I': mmsi_(); break;
case 'J': mmsj_(); break;
case 'K': mmsk_(); break;
case 'L': mmsl_(); break;
default:
fprintf(stderr, "Whoa, attempted to call segment %s\n", segment);
fflush(stderr);
exit(1);
}
fprintf(stderr, "Oops, segment %s didn't call next segment\n", segment);
fflush(stderr);
exit(2);
}
}
What do i need to change in the stubs.c file, so that 'case 'A': mmsa_()' function is declared? If it helps, then mmsa refers to another file i think mmsa.c in the same local directory.
Happy to give more info if you need it. I've not played this game in over 20+ years(!), so any help would be gratefully received.

this is "just" a warning, and the function call doesn't have any parameters, nor any return value is retrieved, so it should be safe to write:
void mmsa_(void);
void mmsb_(void);
...
and so on.
And if you have header files declaring those functions, it's even better as you can include them instead of declaring them directly.
of course you have to link with libraries or objects containing the code of mmsa_ and other functions, or you'll get a link error (the problem would be just moved to the link phase)
as an aside: consider refactoring your code to remove the K&R old-style parameter declaration which is very much outdated and error prone.

Related

switch-case automatic break

Are there any C compilers with extensions that provide the ability to automatically break at the end of each case statement (similar to what Swift has available) or an alterate switch available in a future C spec?
Mostly interested in this to avoid clutter in extensive switch-case scenarios.
I find this works "ok" but would prefer something clearer about the behavior.
#define case break; { } case
#define switch_break switch
switch_break (action)
{
default: printf ("Unknown action");
case action_none : // Nothing
case action_copy : doCopy ();
case action_paste : doPaste ();
case action_none : break; /* C requires a statement after final case */
}
If you hate writing break everytime, wrap the switch statement inside a function. Then break can be replaced with return statements. For example
int switch_func(char c) {
switch(c) {
case 'a': return 1;
case 'b': return 3;
case 'c': return 5;
case 'd': return 7;
. . .
default: return 0;
}
}
Reduces code only if return values are present.

how can I make a char buffer acting as a file?

I'm having trouble converting a char buffer in a FILE* (if this is even possible, of course!).
I have an enumeration defines as such:
typedef enum SchemaType{
SCHEMA_INT,
SCHEMA_REAL,
SCHEMA_STRING,
SCHEMA_BOOLEAN,
SCHEMA_CHAR,
SCHEMA_SIMPLE,
SCHEMA_RECORD,
SCHEMA_ARRAY
} SchemaType;
I have a perfectly functioning function that prints out the enumeration itself (for debugging purposes):
void printSchemaType(FILE* f,SchemaType schemaType){
switch (schemaType){
case SCHEMA_INT: fprintf(f,"int"); break;
case SCHEMA_ARRAY: fprintf(f,"array"); break;
case SCHEMA_BOOLEAN: fprintf(f,"boolean"); break;
case SCHEMA_CHAR: fprintf(f,"char"); break;
case SCHEMA_REAL: fprintf(f,"real"); break;
case SCHEMA_RECORD: fprintf(f,"record"); break;
case SCHEMA_STRING: fprintf(f,"string"); break;
}
}
Now the problem: I need to use the string printed out by fprintf (i.e. "int", "char", "real", ex cetera) as key in an hashtable; for this purpose i would like to store the printed string of printSchemaType() inside a variable, maybe by using sprintf:
char buffer[25];
sprintf(buffer,"%s",printSchemaType_output);
The problem is that I need to get the function output inside a variable! I know I could:
create a new function storeSchemaTypeInsideBuffer(const char* buffer,SchemaType type); with a switch ... case but i would prefer not to because I don't want redundant code for a little thing like this;
change the prototype of "printSchemaType" into
void printSchemaType(const char* buffer,SchemaType schemaType)
but I would prefer not to because there are other functions like printSchemaType with a similar prototype (printTYPE(FILE* f, TYPE typevariable)) and changing its prototype would create a differentiation of prototypes between this only function and the other ones;
The solution I was thinking is to transform a char buffer into a FILE* variable: in this way I would be able to do something like this:
SchemaType=SCHEMA_INT;
char buffer[25];
FILE* bufferActingAsAFile=make_buffer_acts_as_a_File(buffer);
fprintf(bufferActingAsAFile,type); //now in the buffer there is stored "int"
Is something like this even possible in C? If yes, how can I do that?
Not what you asked for, but I would rewrite your printSchemaType function.
Create a new function called SchemaTypeStr (or some other name that fits your naming scheme) like this:
const char* SchemaTypeStr(enum SchemaType type) {
switch(type) {
case SCHEMA_INT: return "int"; break;
case SCHEMA_ARRAY: return "array"; break;
case SCHEMA_BOOLEAN: return "boolean"; break;
case SCHEMA_CHAR: return "char"; break;
case SCHEMA_REAL: return "real"; break;
case SCHEMA_RECORD: return "record"; break;
case SCHEMA_STRING: return "string"; break;
default: abort();
}
}
void printSchemaType(FILE* f,SchemaType schemaType) {
fputs(SchemaTypeStr(schemaType), f);
}
There doesn't seem to be a portable solution. For linux, you can use fmemopen, but for Windows you'll need to use CreateFile, CreateFileMapping and MapViewOfFile.
See similar question here.

My book says to make a program that tracks the amount of money a power user owes to the company using only switch statements

It had the same syntax error at all places marked with double forward slash, syntax error was "case label does not reduce to integer constant"
I can't use if statements because my book is dumb and hates if statements (but only in the switch statement chapter)
#include <stdio.h>
int main()
{
double price;
int power;
char user,hrs;
printf("Enter what kind of consumer (R for residential, C for commercial, I for industrial): ");
scanf("%c",user);
printf("Enter amount of kilowatt hours used: ");
scanf("%d",power);
switch(user)
{
case 'R':
case 'r':
price=6.00+.052*power;
break;
case 'C':
case 'c':
switch(power)
{
case (power>1000): //
price=60.00+(power-1000)*.045;
case power<=1000: //
price=60.00;
}
break;
case 'I':
case 'i':
{
printf("Hours (P for peak, O for off-peak):");
scanf("%c",hrs);
switch(hrs)
{
case 'P':
case 'p':
switch(power)
{
case power>1000: //
price=76.00+.065*(power-1000);
break;
case power<=1000: //
price=76.00;
break;
}
case 'O':
case 'o':
switch(power)
{
case power>1000: //
price=40.00+.028*(power-1000);
break;
case power<=1000: //
price=40.00;
break;
}
break;
default:
printf("Business hour ID not recognized; try again");
break;
}
}
break;
default:
printf("Consumer ID not recognized; try again");
break;
}
printf("Price is %f", price);
return(0);
}
The expressions in your case statements must be constants like 'p', not expressions like power>1000.
If you need to do expressions like power>1000, you should use if/else structures to handle all appropriate cases.
The value of a case statement must be a constant integer.
You are free to use chars (e.g. 'a', 'x', etc) because they will be converted to integers by the compiler (using their ASCII code).
Using any other type of constant will yield unexpected and probably unpleasant results.
Besides, the compiler will complain (and rightly so) if you use the same value in two different case statements. This can be trickier than it seems. For instance :
#define WHATEVER 1
switch (xxx)
{
case 1 : return 1;
case WHATEVER : return 10; // error: duplicate case value
}
Frankly I don't think your exercise is such a good illustration of the practical use of a case statement.
99% of the times, the case values will come from an enumerated type, like for instance:
typedef enum {
CMD_START,
CMD_STOP
} Command;
function process_command (Command c)
{
switch (c)
{
case CMD_START:
do_start();
break;
case CMD_STOP:
do_stop();
break;
default:
panic ("unknown command %d", c);
}
}
When you switch on power, the case targets must be constants.
Since you are actually only interested in the binary outcome of power>1000, you can apply the switch to that:
switch(power>1000)
{
case 1:
price=76.00+.065*(power-1000);
break;
default:
price=76.00;
break;
}
The exercise is meant for you to understand that using a switch this way is very close to if-else. However, only do this to satisfy an academic exercise. No one would actually want to maintain code written this way. It is more natural to use if-else:
if(power>1000)
{
price=76.00+.065*(power-1000);
}
else
{
price=76.00;
}

get optarg with getopt

I have the following code:
char opt;
int bla1,bla2,bla3;
char *myarg = NULL;
while((opt = getopt(argc,argv,"a:b:cd")) != -1)
{
switch (opt)
{
case 'a':
bla1 = atoi(optarg);
break;
case 'b':
myarg = optarg;
break;
case 'c':
bla2 = 1;
break;
case 'd':
bla3 = 1;
break;
default:
break;
}
}
I want to be able to use optarg for case 'b' but in case none is selected to get a default value. Right now requires arg and cannot bypass it and if I replace "b:" with "b" it ignores the argument.
How can I make it work in both situations?
Some but not all versions of getopt allow you to indicate that an argument is optional by putting two colons after the relevant option character.
Wanting an optional argument to an option is a sign that your program is complicated enough that you should consider supporting long option names. Unfortunately there is no standard function to do this, but GNU libc has two: getopt_long and the even more powerful argp. If your software is GPL-compatible, you can get either of them from gnulib and then you don't depend on glibc.

Is this a good practice to validate menus?

i need to show a menu that derive another menu and this derive another menu.
But i'm validating those menus with this form: (Only C standard library)
do{
validOption = 1;
printf("Option #1\n");
printf("Option #2\n");
printf("Option #3\n");
scanf("%i",&option);
switch(option){
case 1: /* Do something */ break;
case 2: /* Do something */ break;
case 3: /* Do something */ break;
default: validOption = 0; printf("Invalid Option\n"); break;
}
}while(!validOption);
But at the time of derive a menu i dont know if use the same option variable and validOption flag.
I think that is not a problem since the derived option variable is going to be overwritten and
I will not need the previous option variable since that option variable has been used for its only
purpose that is join in a specific case.
Now, validOption flag is not a problem too, since when a successfully case occurs means that validOption = 1 (will not iterate more)
and it will match with the previous validOption that have a value of 1 (since has been joined in a case). So will not interfere.
Is a good practice to use the same variables (option, validOption) within derived menus?
Also i need to validate with a getint() function, which make me think that if
is even necessary validate menus seeing it in a practical way.
#include<stdio.h>
int main(){
int option;
int validOption;
do{
printf("Option #1\n");
printf("Option #2\n");
printf("Option #3\n");
scanf("%i",&option);
switch(option){
case 1:
validOption = 1;
do{
printf("Option #1\n");
printf("Option #2\n");
printf("Option #3\n");
scanf("%i",&option);
switch(option){
case 1: validOption = 1; /* Another menu with the same option and validOption variables */ break;
case 2: validOption = 1; /* Do something */ break;
case 3: validOption = 1; /* Do something */ break;
default: validOption = 0; printf("Invalid Option\n"); break;
}
}while(!validOption);
break;
case 2: validOption = 1; /* Do something */ break;
case 3: validOption = 1; /* Do something */ break;
default: validOption = 0; printf("Invalid Option\n"); break;
}
}while(!validOption);
return 0;
}
//I've put validOption = 1; within all cases just for explaining purposes
I would rather call it nested loop than derived.
Coming to your question: Is it valid to re-use same variable within a loop when the 1st value of the variable is no longer needed? (Am I right in rephrasing your question?)
Yes, it's valid. While there's nothing technically wrong with it, I would say No. Because, it causes unnecessary confusion and makes the code readability difficult especially when you it within the same loop (as you do within your outer loop). It becomes even harder as the code base grows. Hence, I would discourage such a coding practice.
You want to validate your integer: Since, you are only going to do pass-by-value (to getint()), there's no problem in using another variable. You can use option1 and option2
Pass the values to getint() to validate it.

Resources