summaryrefslogtreecommitdiff
path: root/src/driver/slbt_txtfile_ctx.c
blob: 53cce0fa4ada2362e8d604133688e0642c612de6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*******************************************************************/
/*  slibtool: a strong libtool implementation, written in C        */
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/

#include <ctype.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

#include <slibtool/slibtool.h>
#include "slibtool_driver_impl.h"
#include "slibtool_errinfo_impl.h"
#include "slibtool_visibility_impl.h"

/********************************************************/
/* Read a text file, and create an in-memory vecotr of  */
/* normalized text lines, stripped of both leading and  */
/* trailing white space.                                */
/********************************************************/

static int slbt_lib_free_txtfile_ctx_impl(
	struct slbt_txtfile_ctx_impl *  ctx,
	struct slbt_input *             mapinfo,
	int                             ret)
{
	if (mapinfo)
		slbt_fs_unmap_input(mapinfo);

	if (ctx) {
		if (ctx->pathbuf)
			free(ctx->pathbuf);

		if (ctx->txtlines)
			free(ctx->txtlines);

		if (ctx->txtlinev)
			free(ctx->txtlinev);

		free(ctx);
	}

	return ret;
}

static int slbt_lib_get_txtfile_ctx_impl(
	const struct slbt_driver_ctx *  dctx,
	const char *                    path,
	int                             fdsrc,
	struct slbt_txtfile_ctx **      pctx)
{
	struct slbt_txtfile_ctx_impl *  ctx;
	struct slbt_input               mapinfo;
	size_t                          nlines;
	char *                          ch;
	char *                          cap;
	char *                          src;
	char *                          mark;
	const char **                   pline;
	char                            dummy;
	int                             cint;

	/* map txtfile file temporarily */
	if (slbt_fs_map_input(dctx,fdsrc,path,PROT_READ,&mapinfo) < 0)
		return SLBT_NESTED_ERROR(dctx);

	/* alloc context */
	if (!(ctx = calloc(1,sizeof(*ctx))))
		return slbt_lib_free_txtfile_ctx_impl(
			ctx,&mapinfo,
			SLBT_BUFFER_ERROR(dctx));

	/* count lines */
	src = mapinfo.size ? mapinfo.addr : &dummy;
	cap = &src[mapinfo.size];

	for (; (src<cap) && isspace((cint=*src)); )
		src++;

	for (ch=src,nlines=0; ch<cap; ch++)
		nlines += (*ch == '\n');

	nlines += (ch[-1] != '\n');

	/* clone path, alloc string buffer and line vector */
	if (!(ctx->pathbuf = strdup(path)))
		return slbt_lib_free_txtfile_ctx_impl(
			ctx,&mapinfo,
			SLBT_SYSTEM_ERROR(dctx,0));

	if (!(ctx->txtlines = calloc(mapinfo.size+1,1)))
		return slbt_lib_free_txtfile_ctx_impl(
			ctx,&mapinfo,
			SLBT_SYSTEM_ERROR(dctx,0));

	if (!(ctx->txtlinev = calloc(nlines+1,sizeof(char *))))
		return slbt_lib_free_txtfile_ctx_impl(
			ctx,&mapinfo,
			SLBT_SYSTEM_ERROR(dctx,0));

	/* copy the source to the allocated string buffer */
	memcpy(ctx->txtlines,mapinfo.addr,mapinfo.size);
	slbt_fs_unmap_input(&mapinfo);

	/* populate the line vector, handle whitespace */
	src = ctx->txtlines;
	cap = &src[mapinfo.size];

	for (; (src<cap) && isspace((cint=*src)); )
		*src++ = '\0';

	for (ch=src,pline=ctx->txtlinev; ch<cap; pline++) {
		for (; (ch<cap) && isspace((cint = *ch)); )
			ch++;

		if (ch < cap)
			*pline = ch;

		for (; (ch<cap) && (*ch != '\n'); )
			ch++;

		mark = ch;

		for (--ch; (ch > *pline) && isspace((cint = *ch)); ch--)
			*ch = '\0';

		if ((ch = mark) < cap)
			*ch++ = '\0';
	}

	/* all done */
	ctx->dctx         = dctx;
	ctx->path         = ctx->pathbuf;
	ctx->tctx.path	  = &ctx->path;
	ctx->tctx.txtlinev = ctx->txtlinev;

	*pctx = &ctx->tctx;

	return 0;
}

slbt_hidden int slbt_impl_get_txtfile_ctx(
	const struct slbt_driver_ctx *  dctx,
	const char *                    path,
	int                             fdsrc,
	struct slbt_txtfile_ctx **      pctx)
{
	return slbt_lib_get_txtfile_ctx_impl(dctx,path,fdsrc,pctx);
}

int slbt_lib_get_txtfile_ctx(
	const struct slbt_driver_ctx *  dctx,
	const char *                    path,
	struct slbt_txtfile_ctx **      pctx)
{
	return slbt_lib_get_txtfile_ctx_impl(dctx,path,(-1),pctx);
}

void slbt_lib_free_txtfile_ctx(struct slbt_txtfile_ctx * ctx)
{
	struct slbt_txtfile_ctx_impl *	ictx;
	uintptr_t			addr;

	if (ctx) {
		addr = (uintptr_t)ctx - offsetof(struct slbt_txtfile_ctx_impl,tctx);
		ictx = (struct slbt_txtfile_ctx_impl *)addr;
		slbt_lib_free_txtfile_ctx_impl(ictx,0,0);
	}
}