/*
* $Id: mlib.c,v 1.4 2025/03/24 04:13:11 snw Exp $
* Function prototypes, structs, and macros for FreeM
* binding library
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: mlib.c,v $
* Revision 1.4 2025/03/24 04:13:11 snw
* Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
*
* Revision 1.3 2025/03/09 19:50:47 snw
* Second phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#include <stdlib.h>
#include "mpsdef.h"
#include "freem.h"
#include "init.h"
#include "transact.h"
#include "version.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
/* the following function prototypes are not in freem.h, as they are intended to be
* private and internal to mlib.c
*/
void mref2str(freem_ref_t *ref, char *key);
void freem_release_io(void);
void freem_return_io(void);
extern int xecline(int typ);
void mref2str(freem_ref_t *ref, char *key)
{
register int i;
for (i = 0; i < 256; i++) key[i] = NUL;
switch (ref->reftype) {
case MREF_RT_LOCAL: /* do nothing for locals, as they have no sigil */
break;
case MREF_RT_GLOBAL:
strcat (key, "^");
break;
case MREF_RT_SSVN:
strcat (key, "^$");
break;
}
if (ref->subscript_count > 0) {
strcat (key, ref->name);
strcat (key, "\202");
for (i = 0; i < ref->subscript_count; i++) {
strcat (key, ref->subscripts[i]);
if (i < ref->subscript_count - 1) strcat (key, "\202");
}
}
else {
strcat (key, ref->name);
}
// ends with EOL
strncat (key, "\201", 2);
}
pid_t freem_init(char *environment_name, char *namespace_name)
{
int ierr_sav;
int errno_sav;
libflag = TRUE;
noclear = TRUE;
frm_filter = TRUE;
direct_mode = FALSE;
errno = 0;
strcpy (shm_env, environment_name);
snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, shm_env);
init (namespace_name);
ierr_sav = ierr;
errno_sav = errno;
freem_release_io ();
if (ierr_sav > OK || errno_sav != 0) {
return -1;
}
else {
return pid;
}
}
short freem_version(char *result)
{
strncpy (result, FREEM_VERSION_ID, 255);
return OK;
}
short freem_get(freem_ref_t *ref)
{
char key[256];
char result[256];
freem_return_io ();
// set up the EOL-delimited string
mref2str (ref, key);
switch (ref->reftype) {
case MREF_RT_LOCAL:
// call into the symbol table to get the local var
symtab (get_sym, key, result);
ref->status = merr ();
break;
case MREF_RT_GLOBAL:
// call into the FreeM global handler; result in &result
global (get_sym, key, result);
ref->status = merr ();
break;
case MREF_RT_SSVN:
// call into the SSVN code
ssvn (get_sym, key, result);
ref->status = merr ();
break;
}
stcnv_m2c (result);
strncpy (ref->value, result, 255);
freem_release_io ();
return ref->status;
}
short freem_set(freem_ref_t *ref)
{
char key[256];
char data[256];
freem_return_io ();
mref2str (ref, key);
snprintf (data, 254, "%s\201", ref->value);
switch (ref->reftype) {
case MREF_RT_LOCAL:
// call into the symbol table to set the local var
symtab (set_sym, key, data);
ref->status = merr ();
break;
case MREF_RT_GLOBAL:
// call into the FreeM global handler; data in &data
global (set_sym, key, data);
ref->status = merr ();
break;
case MREF_RT_SSVN:
// call into the SSVN code
ssvn (set_sym, key, data);
ref->status = merr ();
break;
}
freem_release_io ();
return ref->status;
}
short freem_kill(freem_ref_t *ref)
{
char key[256];
char result[256];
mref2str (ref, key);
freem_return_io ();
switch (ref->reftype) {
case MREF_RT_LOCAL:
// call into the symbol table to kill the local var
symtab (kill_sym, key, result);
ref->status = merr ();
break;
case MREF_RT_GLOBAL:
// call into the FreeM global handler; result in &result
global (kill_sym, key, result);
ref->status = merr ();
break;
case MREF_RT_SSVN:
// call into the SSVN code
ssvn (kill_sym, key, result);
ref->status = merr ();
break;
}
stcnv_m2c (result);
strncpy (ref->value, result, 255);
freem_release_io ();
return ref->status;
}
short freem_data(freem_ref_t *ref)
{
char key[256];
char result[256];
mref2str (ref, key);
freem_return_io ();
switch (ref->reftype) {
case MREF_RT_LOCAL:
// call into the symbol table
symtab (fra_dat, key, result);
ref->status = merr ();
break;
case MREF_RT_GLOBAL:
// call into the FreeM global handler; result in &result
global (fra_dat, key, result);
ref->status = merr ();
break;
case MREF_RT_SSVN:
// call into the SSVN code
ssvn (fra_dat, key, result);
ref->status = merr ();
break;
}
stcnv_m2c (result);
strncpy (ref->value, result, 255);
freem_release_io ();
return ref->status;
}
short freem_order(freem_ref_t *ref)
{
char key[256];
char result[256];
mref2str (ref, key);
freem_return_io ();
switch (ref->reftype) {
case MREF_RT_LOCAL:
// call into the symbol table for $ORDER
symtab (fra_order, key, result);
ref->status = merr ();
break;
case MREF_RT_GLOBAL:
// call into the FreeM global handler; result in &result
global (fra_order, key, result);
ref->status = merr ();
break;
case MREF_RT_SSVN:
// call into the SSVN code
ssvn (fra_order, key, result);
ref->status = merr ();
break;
}
stcnv_m2c (result);
strncpy (ref->value, result, 255);
freem_release_io ();
return ref->status;
}
short freem_query(freem_ref_t *ref)
{
char key[256];
char result[256];
mref2str (ref, key);
freem_return_io ();
switch (ref->reftype) {
case MREF_RT_LOCAL:
// call into the symbol table
symtab (fra_query, key, result);
ref->status = merr ();
break;
case MREF_RT_GLOBAL:
// call into the FreeM global handler; result in &result
global (fra_query, key, result);
ref->status = merr ();
break;
case MREF_RT_SSVN:
// call into the SSVN code
ssvn (fra_query, key, result);
ref->status = merr ();
break;
}
stcnv_m2c (result);
strncpy (ref->value, result, 255);
freem_release_io ();
return ref->status;
}
short freem_lock(freem_ref_t *ref, long lck_timeout)
{
char key[256];
char buf[256];
mref2str (ref, key);
snprintf (buf, 255, "+%s\201", key);
freem_return_io ();
lock (buf, lck_timeout, 'l');
ref->status = merr ();
freem_release_io ();
return ref->status;
}
short freem_unlock(freem_ref_t *ref, long lck_timeout)
{
char key[256];
char buf[256];
mref2str (ref, key);
snprintf (buf, 255, "-%s\201", key);
freem_return_io ();
lock (buf, lck_timeout, 'l');
ref->status = merr ();
freem_release_io ();
return ref->status;
}
short freem_tstart(char *tp_id, short serial, short restartable, char **sym_save)
{
return tp_tstart (tp_id, serial, restartable, sym_save);
}
short freem_trestart(void)
{
return tp_trestart ();
}
short freem_trollback(int tp_levels)
{
return tp_trollback (tp_levels);
}
short freem_tcommit(void)
{
return tp_tcommit ();
}
int freem_tlevel(void)
{
return tp_level;
}
short freem_function(freem_ent_t *ent)
{
register int i;
char buf[STRLEN] = {0};
char tmp[STRLEN] = {0};
char tmp1[STRLEN] = {0};
freem_return_io ();
if (ent->argument_count > 0) {
snprintf (buf, STRLEN - 1, "S %%ZFRMRTN=$$%s(", ent->name);
for (i = 0; i < ent->argument_count; i++) {
strncpy (tmp1, ent->arguments[i], STRLEN - 1);
stcnv_c2m (tmp1);
if (znamenumeric (tmp1) == TRUE) {
/* arguments that are canonical MUMPS numbers don't get quoted */
snprintf (tmp, STRLEN - 1, "%s", ent->arguments[i]);
}
else {
/* string arguments do get quoted */
snprintf (tmp, STRLEN - 1, "\"%s\"", ent->arguments[i]);
}
strcat (buf, tmp);
if(i < ent->argument_count - 1) {
strcat (buf, ",");
}
}
strcat (buf, ")");
}
else {
snprintf (buf, STRLEN - 1, "S %%ZFRMRTN=$$%s", ent->name);
}
stcnv_c2m (buf);
sprintf (tmp, "%%ZFRMXEC\201");
symtab (set_sym, tmp, buf);
snprintf ((char *) ztrap, 12, "^%%ZFRMXEC\201");
xecline (3);
ent->status = merr ();
tmp[0] = NUL;
ent->value[0] = NUL;
snprintf (tmp, 255, "%%ZFRMRTN\201");
symtab (get_sym, tmp, ent->value);
stcnv_m2c (ent->value);
freem_release_io ();
return ent->status;
}
short freem_procedure(freem_ent_t *ent)
{
register int i;
char buf[STRLEN] = {0};
char tmp[STRLEN] = {0};
char tmp1[STRLEN] = {0};
freem_return_io ();
if (ent->argument_count > 0) {
snprintf (buf, STRLEN - 1, "DO %s(", ent->name);
for (i = 0; i < ent->argument_count; i++) {
strncpy (tmp1, ent->arguments[i], STRLEN - 1);
stcnv_c2m (tmp1);
if (znamenumeric (tmp1) == TRUE) {
/* arguments that are canonical MUMPS numbers don't get quoted */
snprintf (tmp, STRLEN - 1, "%s", ent->arguments[i]);
}
else {
/* string arguments do get quoted */
snprintf (tmp, STRLEN - 1, "\"%s\"", ent->arguments[i]);
}
strcat (buf, tmp);
if(i < ent->argument_count - 1) {
strcat (buf, ",");
}
}
strcat (buf, ")");
}
else {
snprintf (buf, STRLEN - 1, "DO %s", ent->name);
}
stcnv_c2m (buf);
sprintf (tmp, "%%ZFRMXEC\201");
symtab (set_sym, tmp, buf);
snprintf ((char *) ztrap, 12, "^%%ZFRMXEC\201");
xecline (3);
ent->status = merr ();
tmp[0] = NUL;
ent->value[0] = NUL;
freem_release_io ();
return ent->status;
}
short freem_errmsg(int code, char *msg)
{
char emtmp[256];
char cvtmp[256];
if (code > MAXERR || code < 0) {
return FALSE;
}
stcpy (cvtmp, errmes[code]);
stcnv_m2c (cvtmp);
merr_num_to_code (code, emtmp);
sprintf (msg, "%s: %s", emtmp, cvtmp);
return TRUE;
}
void freem_release_io(void)
{
set_io (UNIX);
}
void freem_return_io(void)
{
set_io (MUMPS);
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>